React Redux 中間件思想遇見 Web Worker 的靈感(附demo)

寫在最前

原文首發(fā)于作者的知乎專欄:React Redux 中間件思想遇見 Web Worker 的靈感(附demo)输虱,感興趣的同學(xué)可以知乎關(guān)注,進行交流窗怒。

熟悉 React 技術(shù)棧的同學(xué)写半,想必對 Redux 數(shù)據(jù)流框架并不陌生。其倡導(dǎo)的單向數(shù)據(jù)流等思想獨樹一幟埃难,雖然樣板代碼會有一定程度上的增多,但是對于開發(fā)效率和調(diào)試效率的提高是顯著的涤久。同時還帶來了很多諸如 “時間旅行”涡尘,“ undo/redo ” 等黑魔法。

其實這還只是表象响迂。如果你深入去了解 Redux 的設(shè)計理念考抄,探索中間件奧秘,玩轉(zhuǎn)高階 reducer 等等蔗彤,迎接你的就會是另一扇門川梅。透過它,函數(shù)式編程思想之光傾斜如注然遏。

思想背景

但是隨著這個 web app 復(fù)雜度的提升贫途,數(shù)據(jù)計算量壓力徒增,你所設(shè)計的 Reducer 變得臃腫不堪待侵。好吧丢早,我們可以拆分 Reducer 使得代碼看上去更加舒服。可是計算量呢怨酝?也許有一些“夢魘”傀缩,瓶頸般永遠無法消除。

冥冥之中农猬,“各種處理計算既然注定在同一時空赡艰,那么能否永遠平行?”

曾幾何時斤葱,你是否聽說過 JS 單線程異步瞄摊?聽說過瀏覽器卡頓或卡死?聽說過 60 fps苦掘?

其實一個很嚴峻的事實是:根據(jù) 60 fps 計算,每一幀留給我們 JS 執(zhí)行的時間為 16ms(甚至更少)楔壤。那么一旦當 Reducer 計算時間過長鹤啡,必然會影響瀏覽器渲染。

多線程思路

關(guān)于瀏覽器主線程蹲嚣、render queue递瑰、event loop、call stack 等內(nèi)容隙畜,本文不再復(fù)述抖部,因為里面的知識完全都夠?qū)懸槐緯恕<俣ㄗx者對其有一二認知议惰,那么你也不難理解我們即將登場的救星—— Web Worker!

我們先來簡單認識一下 web worker:

2008 年 W3C 制定出第一個 HTML5 草案開始慎颗,HTML5 承載了越來越多嶄新的特性和功能。其中言询,最重要的一個便是對多線程的支持俯萎。在 HTML5 中提出了工作線程(Web Worker)的概念,并且規(guī)范出 Web Worker 的三大主要特征:

  • 能夠長時間運行(響應(yīng))运杭;
  • 理想的啟動性能夫啊;
  • 以及理想的內(nèi)存消耗。

Work 線程可以執(zhí)行任務(wù)而不干擾用戶界面辆憔。

于是撇眯,腦洞大開,能否將我們的 Redux Reducer 計算狀態(tài)部分放進 Worker 線程中處理呢虱咧?

答案是肯定的熊榛。
那么要如何實施呢?

我們先來看一下經(jīng)典的 Redux workflow彤钟,如下圖:

redux 流程圖

如果要接入 Web Work来候,那么我們改動流程圖如下:

redux + worker 流程圖

具體實現(xiàn)和一個demo

當然,有了思路逸雹,還需要在實戰(zhàn)中演練营搅。

我使用 “N-皇后問題” 模擬大型計算云挟,并且實現(xiàn)的 demo 中可以任意設(shè)置 n 值,增加計算耗時转质。
如果你不理解此算法也沒有關(guān)系园欣,只需要知道N-皇后問題這個算法的計算耗時很長,且和 n 值相關(guān):n 越大休蟹,計算成本越大沸枯。

除了一個極其耗時的計算,頁面中還運行這么幾個模塊赂弓,來實現(xiàn)復(fù)雜的渲染邏輯操作:

  • 一個實時每16毫秒绑榴,顯示計數(shù)(每秒增加1)的 blinker 模塊;
  • 一個定時每500毫秒盈魁,更新背景顏色的 counter 模塊翔怎;
  • 一個永久往復(fù)運動的 slider 模塊;
  • 一個每16毫秒翻轉(zhuǎn)5度的 spinner 模塊
頁面過程

這些模塊都定時頻繁地更新 dom 樣式杨耙,進行大量復(fù)雜的渲染計算赤套。正常情況下,由于 JS 主線程進行N-皇后計算珊膜,這些渲染過程都將被卡頓容握。

同時,我設(shè)置“N-皇后問題”的 n 值车柠,來觀察在計算時這些模塊的表現(xiàn)(是否卡頓)剔氏。在不開啟 Work 線程的情況下,n 設(shè)置為13時堪遂,有 gif 圖介蛉,左半部分:

off.gif

我們非常清晰地看到:由于瀏覽器 call stack 進行 n=13 的皇后問題計算,而無法“按時”渲染溶褪,所以造成了這幾個模塊的卡頓币旧,這些模塊都無法更新狀態(tài)。在這個卡頓過程中猿妈,用戶的任何事件(如點擊吹菱,敲鍵盤等)都無法被瀏覽器響應(yīng)。這就是用戶體會到的“慢”彭则!

如果我把 n 值設(shè)置的大與13呢鳍刷,比如24?
千萬不要這么做俯抖!因為你的瀏覽器會被卡死输瓜!我使用 Mac Pro 8G 內(nèi)存情況下,設(shè)置到14,瀏覽器就無法響應(yīng)了尤揣。

在開啟 Work 線程時搔啊,請參考上 gif 圖右半部分,幾個模塊的渲染絲毫不受影響北戏。完美達到了我們的目的负芋。

因為 Reducer 的超級耗時計算被放入 Worker 線程當中,所以絲毫沒有影響瀏覽器的渲染和響應(yīng)嗜愈。完全解決了用戶覺得“電腦慢”的問題旧蛾。

看到了如此完美的對比,也許你想問 Web Worker 的兼容性如何呢蠕嫁?

兼容性

總結(jié)

其實锨天,這篇文章的意義并不在于這個 demo 和應(yīng)用。而是在啟發(fā)一種新的想法的同時剃毒,review 了很多 JS 當中關(guān)鍵概念和基本知識绍绘。比如:單線程異步、宿主環(huán)境迟赃、60 fps、一個算法等等厂镇。

更值得一提的是纤壁,如果你去深入 demo 代碼,你更會發(fā)現(xiàn) Redux 設(shè)計精妙的思想捺信,比如我們將 Web Worker 的應(yīng)用抽象出一個公共庫:Redux-Worker酌媒,并包裝為 Redux 的中間件(middleware),所有 React Redux 都可以無侵入迄靠,采用中間件的思想使用:

import { applyWorker } from 'redux-worker';
const enhancerWithWorker = compose(
    applyMiddleware(thunk, logger),
    applyWorker(worker)
);

const store = createStore(rootReducer, {}, enhancerWithWorker);

當然秒咨,Redux-Worker 這個中間件的實現(xiàn)原理更是巧妙,這里不再展開掌挚。感興趣的同學(xué)可以參考我的此項目 Github 倉庫雨席。我 fork 了此庫源碼,并在核心邏輯加入了中文注釋吠式,感興趣的同學(xué)可以關(guān)注陡厘。

我的其他關(guān)于 React 文章:

Happy Coding!

PS:
作者Github倉庫知乎問答鏈接
歡迎各種形式交流糙置。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市是目,隨后出現(xiàn)的幾起案子谤饭,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揉抵,死亡現(xiàn)場離奇詭異亡容,居然都是意外死亡,警方通過查閱死者的電腦和手機功舀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門萍倡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辟汰,你說我怎么就攤上這事列敲。” “怎么了帖汞?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵戴而,是天一觀的道長。 經(jīng)常有香客問我翩蘸,道長所意,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任催首,我火速辦了婚禮扶踊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘郎任。我一直安慰自己秧耗,他們只是感情好,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布舶治。 她就那樣靜靜地躺著分井,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霉猛。 梳的紋絲不亂的頭發(fā)上尺锚,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機與錄音惜浅,去河邊找鬼瘫辩。 笑死,一個胖子當著我的面吹牛坛悉,可吹牛的內(nèi)容都是我干的杭朱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼吹散,長吁一口氣:“原來是場噩夢啊……” “哼弧械!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起空民,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤刃唐,失蹤者是張志新(化名)和其女友劉穎羞迷,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體画饥,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡衔瓮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了抖甘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片热鞍。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖衔彻,靈堂內(nèi)的尸體忽然破棺而出薇宠,到底是詐尸還是另有隱情,我是刑警寧澤艰额,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布澄港,位于F島的核電站,受9級特大地震影響柄沮,放射性物質(zhì)發(fā)生泄漏回梧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一祖搓、第九天 我趴在偏房一處隱蔽的房頂上張望狱意。 院中可真熱鬧,春花似錦拯欧、人聲如沸髓涯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蚓再,卻和暖如春滑肉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摘仅。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工靶庙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娃属。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓六荒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矾端。 傳聞我的和親對象是個殘疾皇子掏击,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容