一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務(wù)器之家 - 編程語言 - JavaScript - React - 100行代碼實(shí)現(xiàn)React核心調(diào)度功能

100行代碼實(shí)現(xiàn)React核心調(diào)度功能

2021-12-16 22:22魔術(shù)師卡頌卡頌 React

想必大家都知道React有一套基于Fiber架構(gòu)的調(diào)度系統(tǒng),本文會(huì)用100行代碼實(shí)現(xiàn)這套調(diào)度系統(tǒng),讓你快速了解React的調(diào)度原理。

100行代碼實(shí)現(xiàn)React核心調(diào)度功能

大家好,我卡頌。

想必大家都知道React有一套基于Fiber架構(gòu)的調(diào)度系統(tǒng)。這套調(diào)度系統(tǒng)的基本功能包括:

  • 更新有不同優(yōu)先級(jí)
  • 一次更新可能涉及多個(gè)組件的render,這些render可能分配到多個(gè)宏任務(wù)中執(zhí)行(即時(shí)間切片)
  • 高優(yōu)先級(jí)更新會(huì)打斷進(jìn)行中的低優(yōu)先級(jí)更新

本文會(huì)用100行代碼實(shí)現(xiàn)這套調(diào)度系統(tǒng),讓你快速了解React的調(diào)度原理。

我知道你不喜歡看大段的代碼,所以本文會(huì)以圖+代碼片段的形式講解。

文末有完整的在線Demo,你可以自己上手玩玩。

開整!

準(zhǔn)備工作

我們用work這一數(shù)據(jù)結(jié)構(gòu)代表一份工作,work.count代表這份工作要重復(fù)做某件事的次數(shù)。

在Demo中要重復(fù)做的事是“執(zhí)行insertItem方法,向頁面插入”:

  1. const insertItem = (content: string) => {
  2. const ele = document.createElement('span');
  3. ele.innerText = `${content}`;
  4. contentBox.appendChild(ele);
  5. };

所以,對(duì)于如下work:

  1. const work1 = {
  2. count: 100
  3. }

代表:執(zhí)行100次insertItem向頁面插入100個(gè)。

work可以類比React的一次更新,work.count類比這次更新要render的組件數(shù)量。所以Demo是對(duì)React更新流程的類比

來實(shí)現(xiàn)第一版的調(diào)度系統(tǒng),流程如圖:

100行代碼實(shí)現(xiàn)React核心調(diào)度功能

包括三步:

  1. 向workList隊(duì)列(用于保存所有work)插入work
  2. schedule方法從workList中取出work,傳遞給perform
  3. perform方法執(zhí)行完work的所有工作后重復(fù)步驟2

代碼如下:

  1. // 保存所有work的隊(duì)列
  2. const workList: work[] = [];
  3. // 調(diào)度
  4. function schedule() {
  5. // 從隊(duì)列尾取一個(gè)work
  6. const curWork = workList.pop();
  7. if (curWork) {
  8. perform(curWork);
  9. }
  10. }
  11. // 執(zhí)行
  12. function perform(work: Work) {
  13. while (work.count) {
  14. work.count--;
  15. insertItem();
  16. }
  17. schedule();
  18. }

為按鈕綁定點(diǎn)擊交互,最基本的調(diào)度系統(tǒng)就完成了:

  1. button.onclick = () => {
  2. workList.unshift({
  3. count: 100
  4. })
  5. schedule();
  6. }

點(diǎn)擊button就能插入100個(gè)。

用React類比就是:點(diǎn)擊button,觸發(fā)同步更新,100個(gè)組件render

接下來我們將其改造成異步的。

Scheduler

React內(nèi)部使用Scheduler完成異步調(diào)度。

Scheduler是獨(dú)立的包。所以可以用他改造我們的Demo。

Scheduler預(yù)置了5種優(yōu)先級(jí),從上往下優(yōu)先級(jí)降低:

  • ImmediatePriority,最高的同步優(yōu)先級(jí)
  • UserBlockingPriority
  • NormalPriority
  • LowPriority
  • IdlePriority,最低優(yōu)先級(jí)

scheduleCallback方法接收優(yōu)先級(jí)與回調(diào)函數(shù)fn,用于調(diào)度fn:

  1. // 將回調(diào)函數(shù)fn以LowPriority優(yōu)先級(jí)調(diào)度
  2. scheduleCallback(LowPriority, fn)

在Scheduler內(nèi)部,執(zhí)行scheduleCallback后會(huì)生成task這一數(shù)據(jù)結(jié)構(gòu):

  1. const task1 = {
  2. expiration: startTime + timeout,
  3. callback: fn
  4. }

task1.expiration代表task1的過期時(shí)間,Scheduler會(huì)優(yōu)先執(zhí)行過期的task.callback。

expiration中startTime為當(dāng)前開始時(shí)間,不同優(yōu)先級(jí)的timeout不同。

比如,ImmediatePriority的timeout為-1,由于:

  1. startTime - 1 < startTime

所以ImmediatePriority會(huì)立刻過期,callback立刻執(zhí)行。

而IdlePriority對(duì)應(yīng)timeout為1073741823(最大的31位帶符號(hào)整型),其callback需要非常長時(shí)間才會(huì)執(zhí)行。

callback會(huì)在新的宏任務(wù)中執(zhí)行,這就是Scheduler調(diào)度的原理。

用Scheduler改造Demo

改造后的流程如圖:

100行代碼實(shí)現(xiàn)React核心調(diào)度功能

改造前,work直接從workList隊(duì)列尾取出:

  1. // 改造前
  2. const curWork = workList.pop();

改造后,work可以擁有不同優(yōu)先級(jí),通過priority字段表示。

比如,如下work代表「以NormalPriority優(yōu)先級(jí)插入100個(gè)」:

  1. const work1 = {
  2. count: 100,
  3. priority: NormalPriority
  4. }

改造后每次都使用最高優(yōu)先級(jí)的work:

  1. // 改造后
  2. // 對(duì)workList排序后取priority值最小的(值越小,優(yōu)先級(jí)越高)
  3. const curWork = workList.sort((w1, w2) => {
  4. return w1.priority - w2.priority;
  5. })[0];

改造后流程的變化

由流程圖可知,Scheduler不再直接執(zhí)行perform,而是通過執(zhí)行scheduleCallback調(diào)度perform.bind(null, work)。

即,滿足一定條件的情況下,生成新task:

  1. const someTask = {
  2. callback: perform.bind(null, work),
  3. expiration: xxx
  4. }

同時(shí),work的工作也是可中斷的。在改造前,perform會(huì)同步執(zhí)行完work中的所有工作:

  1. while (work.count) {
  2. work.count--;
  3. insertItem();
  4. }

改造后,work的執(zhí)行流程隨時(shí)可能中斷:

  1. while (!needYield() && work.count) {
  2. work.count--;
  3. insertItem();
  4. }

needYield方法的實(shí)現(xiàn)(何時(shí)會(huì)中斷)請(qǐng)參考文末在線Demo

高優(yōu)先級(jí)打斷低優(yōu)先級(jí)的例子

舉例來看一個(gè)高優(yōu)先級(jí)打斷低優(yōu)先級(jí)的例子:

插入一個(gè)低優(yōu)先級(jí)work,屬性如下

  1. const work1 = {
  2. count: 100,
  3. priority: LowPriority
  4. }

經(jīng)歷schedule(調(diào)度),perform(執(zhí)行),在執(zhí)行了80次工作時(shí),突然插入一個(gè)高優(yōu)先級(jí)work,此時(shí):

  1. const work1 = {
  2. // work1已經(jīng)執(zhí)行了80次工作,還差20次執(zhí)行完
  3. count: 20,
  4. priority: LowPriority
  5. }
  6. // 新插入的高優(yōu)先級(jí)work
  7. const work2 = {
  8. count: 100,
  9. priority: ImmediatePriority
  10. }

work1工作中斷,繼續(xù)schedule。由于work2優(yōu)先級(jí)更高,會(huì)進(jìn)入work2對(duì)應(yīng)perform,執(zhí)行100次工作

work2執(zhí)行完后,繼續(xù)schedule,執(zhí)行work1剩余的20次工作

在這個(gè)例子中,我們需要區(qū)分2個(gè)「打斷」的概念:

在步驟3中,work1執(zhí)行的工作被打斷。這是微觀角度的「打斷」

由于work1被打斷,所以繼續(xù)schedule。下一個(gè)執(zhí)行工作的是更高優(yōu)的work2。work2的到來導(dǎo)致work1被打斷,這是宏觀角度的「打斷」

之所以要區(qū)分「宏/微觀」,是因?yàn)椤肝⒂^的打斷」不一定意味著「宏觀的打斷」。

比如:work1由于時(shí)間切片用盡,被打斷。沒有其他更高優(yōu)的work與他競爭schedule的話,下一次perform還是work1。

這種情況下微觀下多次打斷,但是宏觀來看,還是同一個(gè)work在執(zhí)行。這就是「時(shí)間切片」的原理。

調(diào)度系統(tǒng)的實(shí)現(xiàn)原理

以下是調(diào)度系統(tǒng)的完整實(shí)現(xiàn)原理:

100行代碼實(shí)現(xiàn)React核心調(diào)度功能

對(duì)照流程圖來看:

100行代碼實(shí)現(xiàn)React核心調(diào)度功能

總結(jié)

本文是React調(diào)度系統(tǒng)的簡易實(shí)現(xiàn),主要包括兩個(gè)階段:

  • schedule
  • perform

如果你對(duì)代碼的具體實(shí)現(xiàn)感興趣,下面是完整Demo地址。

參考資料

[1]Scheduler:

https://github.com/facebook/react/tree/main/packages/scheduler

[2]完整Demo地址:

https://codesandbox.io/s/xenodochial-alex-db74g?file=/src/index.ts

原文鏈接:https://mp.weixin.qq.com/s/uuxHlanqyN2HneYOz7DMVw

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美牛逼aa| 毛片一级免费 | 免费视频完整版在线观看网站 | 91久久偷偷做嫩草影院免费 | 91香蕉视频在线观看 | 色戒真做gif动图 | 动漫美女强行被吸乳做羞羞事 | 亚洲国产精久久久久久久 | 色婷婷婷丁香亚洲综合不卡 | uoco福利姬 | 果冻传媒第一二三专区 | 免费看a视频 | 狠狠色成人综合网图片区 | 精品久久久久久久久久久久久久久 | 农夫成人网 | 99久热只有精品视频免费观看17 | 国产91区 | 国产永久一区二区三区 | 3黑人巨大vs北岛玲 3d肉浦团在线观看 3d动漫免费 | 超高清欧美同性videos | 精品视频免费在线观看 | 久久综合狠狠综合久久综合88 | 2022最新国产在线不卡a | 幻女free性俄罗斯第一次摘花 | 成人150p | 男人的天堂在线观看入口 | 色老板在线观看 | 国内久久精品 | 小辣椒精品福利视频导航 | 好男人资源免费观看 | a男人的天堂久久a毛片 | 被老头操 | 色女阁| 91视频a| 美女尿口照片 | 午夜亚洲精品久久久久久 | 色多多在线观看视频 | 亚洲欧美一区二区久久 | 免费一看一级毛片人 | 国产91一区二区在线播放不卡 | aⅴ视频在线免播放观看 |