最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入理解React19中任務(wù)調(diào)度器Scheduler的實(shí)現(xiàn)

 更新時(shí)間:2026年03月02日 09:39:35   作者:秀秀不只會(huì)前端  
本文主要介紹了深入理解React任務(wù)調(diào)度器Scheduler的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

Scheduler = 最小堆 + MessageChannel + 時(shí)間片檢查

它的目標(biāo)只有一個(gè):推進(jìn)任務(wù),但永遠(yuǎn)別餓死瀏覽器。

調(diào)度任務(wù)

React 19 最新 Scheduler 源碼**(packages/scheduler)** 中,普通任務(wù)(非 Immediate,同步優(yōu)先級(jí)之外的任務(wù))的完整調(diào)度鏈:

unstable_scheduleCallback
  ↓
requestHostCallback
  ↓
schedulePerformWorkUntilDeadline
  ↓
performWorkUntilDeadline
  ↓
flushWork
  ↓
workLoop
  ↓
shouldYieldToHost
  ↓
advanceTimers

Scheduler 本質(zhì)是一個(gè)“帶時(shí)間片控制的最小堆 + 宏任務(wù)驅(qū)動(dòng)循環(huán)”調(diào)度器。

一、調(diào)度的起點(diǎn):unstable_scheduleCallback

源碼位置(React 19):

/packages/scheduler/src/forks/Scheduler.js
let getCurrentTime = () => performance.now();

// 為所有任務(wù)維護(hù)了連個(gè)最小堆(每次從隊(duì)列里面取出來(lái)的都是優(yōu)先級(jí)最高(時(shí)間即將過(guò)期))
// timerQueue     // 延時(shí)任務(wù)隊(duì)列(task.startTime > now) —— 按 startTime 排序(延遲最小的先看)
// taskQueue      // 立即可執(zhí)行的任務(wù)(task.startTime <= now)—— 按 expirationTime 排序(最緊急的先執(zhí)行)

// Timeout 對(duì)應(yīng)的值
var IMMEDIATE_PRIORITY_TIMEOUT = -1;
var USER_BLOCKING_PRIORITY_TIMEOUT = 250;
var NORMAL_PRIORITY_TIMEOUT = 5000;
var LOW_PRIORITY_TIMEOUT = 10000;
var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt; // 1073741823

/**
? * 調(diào)度任務(wù)的入口
? * ?@param? {*} priorityLevel 優(yōu)先級(jí)等級(jí)
? * ?@param? {*} callback 任務(wù)回調(diào)函數(shù)
? * ?@param? {*} options { delay: number } 該對(duì)象有 delay 屬性,表示要延遲的時(shí)間(決定 expirationTime)
? * ?@returns
? */
 function unstable_scheduleCallback(priorityLevel, callback, options) {
  // 獲取當(dāng)前的時(shí)間
  var currentTime = getCurrentTime();

  var startTime;
  // 設(shè)置起始時(shí)間 startTime:如果有延時(shí) delay,起始時(shí)間需要添加上這個(gè)延時(shí),否則起始時(shí)間就是當(dāng)前時(shí)間
  if (typeof options === "object" && options !== null) {
    var delay = options.delay;
    if (typeof delay === "number" && delay > 0) {
      startTime = currentTime + delay;
    } else {
      startTime = currentTime;
    }
  } else {
    startTime = currentTime;
  }

  var timeout;
  // 根據(jù)傳入的優(yōu)先級(jí)等級(jí)來(lái)設(shè)置不同的 timeout
  switch (priorityLevel) {
    case ImmediatePriority:
      timeout = IMMEDIATE_PRIORITY_TIMEOUT; // -1
      break;
    case UserBlockingPriority:
      timeout = USER_BLOCKING_PRIORITY_TIMEOUT; // 250
      break;
    case IdlePriority:
      timeout = IDLE_PRIORITY_TIMEOUT; // 1073741823
      break;
    case LowPriority:
      timeout = LOW_PRIORITY_TIMEOUT; // 10000
      break;
    case NormalPriority:
    default:
      timeout = NORMAL_PRIORITY_TIMEOUT; // 5000
      break;
  }
  // 接下來(lái)就計(jì)算出過(guò)期時(shí)間
  // 只有 ImmediatePriority 任務(wù) 比當(dāng)前時(shí)間要早,其他任務(wù)都會(huì)不同程度的延遲
  var expirationTime = startTime + timeout;

  // 創(chuàng)建一個(gè)新的任務(wù)
  var newTask = {
    id: taskIdCounter++, // 任務(wù) id
    callback, // 執(zhí)行任務(wù)回調(diào)函數(shù) export type Callback = boolean => ?Callback;
    priorityLevel, // 任務(wù)的優(yōu)先級(jí)
    startTime, // 任務(wù)開(kāi)始時(shí)間
    expirationTime, // 任務(wù)的過(guò)期時(shí)間
    sortIndex: -1, // 用于小頂堆優(yōu)先級(jí)排序,始終從任務(wù)隊(duì)列中拿出最優(yōu)先的任務(wù)
  };
  if (enableProfiling) {
    newTask.isQueued = false;
  }

  if (startTime > currentTime) {
    // 說(shuō)明這是一個(gè)延時(shí)任務(wù)
    newTask.sortIndex = startTime;
    // 將該任務(wù)推入到 timerQueue 的任務(wù)隊(duì)列中
    push(timerQueue, newTask);
    if (peek(taskQueue) === null && newTask === peek(timerQueue)) {
      // 說(shuō)明 taskQueue 里面的任務(wù)已經(jīng)全部執(zhí)行完畢,然后從 timerQueue 里面取出一個(gè)優(yōu)先級(jí)最高的任務(wù)作為此時(shí)的 newTask
      if (isHostTimeoutScheduled) {
        cancelHostTimeout();
      } else {
        isHostTimeoutScheduled = true;
      }
      // 如果是延時(shí)任務(wù),調(diào)用 requestHostTimeout 進(jìn)行延時(shí)任務(wù)的調(diào)度
      requestHostTimeout(handleTimeout, startTime - currentTime);
    }
  } else {
    // 說(shuō)明不是延時(shí)任務(wù)
    newTask.sortIndex = expirationTime; // 設(shè)置了 sortIndex 后,在任務(wù)隊(duì)列里面進(jìn)行一個(gè)排序
    push(taskQueue, newTask);
    if (enableProfiling) {
      markTaskStart(newTask, currentTime);
      newTask.isQueued = true;
    }
    // 最終調(diào)用 requestHostCallback 進(jìn)行普通任務(wù)的調(diào)度
    if (!isHostCallbackScheduled && !isPerformingWork) {
      isHostCallbackScheduled = true;
      requestHostCallback();
    }
  }

  // 向外部返回任務(wù)
  return newTask;
}

它的職責(zé)是:

  1. 根據(jù)優(yōu)先級(jí)計(jì)算 timeout
  2. 構(gòu)造一個(gè) Task 對(duì)象
  3. 放入任務(wù)到對(duì)應(yīng)的最小堆
  4. 請(qǐng)求宿主開(kāi)始調(diào)度(requestHostCallback 普通任務(wù) / requestHostTimeout 延時(shí)任務(wù))

任務(wù)執(zhí)行時(shí)刻:

IMMEDIATE_PRIORITY_TIMEOUT -> currentTime -> USER_BLOCKING_PRIORITY_TIMEOUT -> IDLE_PRIORITY_TIMEOUT

二、普通任務(wù)調(diào)用 requestHostCallback

當(dāng)普通任務(wù)進(jìn)入 taskQueue 后,調(diào)用 requestHostCallback,然后調(diào)用 schedulePerformWorkUntilDeadline

/**
? * 
? * ?@param? ?{*}? callback 是在調(diào)用的時(shí)候傳入的 flushWork
? * requestHostCallback 這個(gè)函數(shù)沒(méi)有做什么事情,主要就是調(diào)用 schedulePerformWorkUntilDeadline
? */
 function requestHostCallback() {
  if (!isMessageLoopRunning) {
    isMessageLoopRunning = true;
    schedulePerformWorkUntilDeadline();// 實(shí)例化 MessageChannel 進(jìn)行后面的調(diào)度
  }
}

let schedulePerformWorkUntilDeadline; // undefined
if (typeof localSetImmediate === 'function') {
  // Node.js and old IE.
  schedulePerformWorkUntilDeadline = () => {
    localSetImmediate(performWorkUntilDeadline);
  };
} else if (typeof MessageChannel !== 'undefined') {
  // 大多數(shù)情況下,使用的是 MessageChannel
  const channel = new MessageChannel();
  const port = channel.port2;
  channel.port1.onmessage = performWorkUntilDeadline;
  schedulePerformWorkUntilDeadline = () => {
    port.postMessage(null);
  };
} else {
  // setTimeout 進(jìn)行兜底
  schedulePerformWorkUntilDeadline = () => {
    localSetTimeout(performWorkUntilDeadline, 0);
  };
}

schedulePerformWorkUntilDeadline 根據(jù)不同的環(huán)境選擇不同的生成宏任務(wù)的方式。大多數(shù)都是 MessageChannel :

  • 每一次調(diào)度推進(jìn)
  • 都是一個(gè)新的宏任務(wù)
  • 瀏覽器中間有機(jī)會(huì) paint

三、延時(shí)任務(wù)調(diào)用 requestHostTimeout & handleTimeout

React Scheduler 不直接使用 setTimeout,而是抽象成 HostConfig,可在不同環(huán)境實(shí)現(xiàn)。

requestHostTimeout(callback, ms) 這個(gè)函數(shù)會(huì)安排一個(gè)底層超時(shí)回調(diào)。

在瀏覽器環(huán)境下它一般等價(jià)于:

const timeoutID = setTimeout(callback, ms);

注意:這是 ?嚴(yán)格意義上的延時(shí)調(diào)度?,用于把 timerQueue 的任務(wù)喚醒進(jìn) taskQueue。

requestHostTimeout 實(shí)際上就是調(diào)用 setTimoutout,然后在 setTimeout 中,調(diào)用傳入的 handleTimeout。

注意:延時(shí)任務(wù)只需要“不會(huì)提前執(zhí)行”,而不需要“精準(zhǔn)執(zhí)行”,所以這里使用了 setTimeout,setTimeout 只是負(fù)責(zé)“喚醒” Scheduler,不負(fù)責(zé)精度和優(yōu)先級(jí)(expirationTime 控制)控制,鑒于負(fù)責(zé)延時(shí)和必須是宏任務(wù)的特性,這里使用 setTimeout 最合適。

React 的調(diào)度精度來(lái)自:MessageChannel + 時(shí)間片檢查 + expirationTime 。

handleTimeout 是真正被 setTimeout 調(diào)用的函數(shù):

function handleTimeout(currentTime) {
  // 遍歷 timerQueue,將時(shí)間已經(jīng)到了的延時(shí)任務(wù)放入到 taskQueue
  advanceTimers(currentTime);
  if (!isHostCallbackScheduled) {
    if (taskQueue.length > 0) {
      // 采用調(diào)度普通任務(wù)的方式進(jìn)行調(diào)度
      requestHostCallback(flushWork);
    } else {
      // 如果任務(wù)仍然是延時(shí),繼續(xù)設(shè)置 HostTimeout
      const firstTimer = peek(timerQueue);
      if (firstTimer !== null) {
        const nextDelay = firstTimer.startTime - currentTime;
        requestHostTimeout(handleTimeout, nextDelay);
      }
    }
  }
}

四、performWorkUntilDeadline

這是 Scheduler 的“驅(qū)動(dòng)心跳”。

let startTime = -1;
const performWorkUntilDeadline = () => {
  if (enableRequestPaint) {
    needsPaint = false;
  }
  if (isMessageLoopRunning) {
    const currentTime = getCurrentTime();
    // 這里的 startTime 并非 unstable_scheduleCallback 方法里面的 startTime
    // 而是一個(gè)全局變量,默認(rèn)值為 -1
    // 用來(lái)測(cè)量任務(wù)的執(zhí)行時(shí)間,從而能夠知道主線程被阻塞了多久
    startTime = currentTime;
    let hasMoreWork = true;
    try {
      // flushWork 為任務(wù)中轉(zhuǎn),本質(zhì)上內(nèi)部繼續(xù)調(diào)用 workLoop 判斷任務(wù)執(zhí)行情況
      hasMoreWork = flushWork(currentTime);
    } finally {
      if (hasMoreWork) {
        // 上面剛剛講過(guò)的方法,根據(jù)不同的環(huán)境選擇不同的生成宏任務(wù)的方式(MessageChannel)
        schedulePerformWorkUntilDeadline();
      } else {
        isMessageLoopRunning = false;
      }
    }
  }
};

它做三件事:

  1. 設(shè)置本次調(diào)度的時(shí)間起點(diǎn)
  2. 調(diào)用 flushWork
  3. 如果還有任務(wù) → 再發(fā)一個(gè) MessageChannel

五、flushWork 和 workLoop 執(zhí)行任務(wù)循環(huán)

// flushWork 是個(gè)中轉(zhuǎn),它真正執(zhí)行的是  workLoop
function flushWork(initialTime) {
  // ...
  // 各種開(kāi)關(guān)、報(bào)錯(cuò)捕獲...
  // 其實(shí)核心就是 workLoop
  return workLoop(initialTime);
}

// 不斷從任務(wù)隊(duì)列中取出任務(wù)執(zhí)行
function workLoop(initialTime: number) {
  // initialTime 開(kāi)始執(zhí)行任務(wù)的時(shí)間
  let currentTime = initialTime;
  // advanceTimers 是用來(lái)遍歷 timerQueue,判斷是否有已經(jīng)到期的任務(wù)
  // 如果有,將這個(gè)任務(wù)放入到 taskQueue
  advanceTimers(currentTime);
  currentTask = peek(taskQueue);
  while (currentTask !== null) {
    if (!enableAlwaysYieldScheduler) {
      if (currentTask.expirationTime > currentTime && shouldYieldToHost()) {
        // 任務(wù)沒(méi)有過(guò)期,并且需要中斷任務(wù),歸還主線程
        break;
      }
    }
    // 返回任務(wù)本身,致使任務(wù)之后可以接著繼續(xù)執(zhí)行
    const callback = currentTask.callback;
    if (typeof callback === 'function') {
      currentTask.callback = null;
      currentPriorityLevel = currentTask.priorityLevel;
      const didUserCallbackTimeout = currentTask.expirationTime <= currentTime;
      if (enableProfiling) {
        markTaskRun(currentTask, currentTime);
      }
      // 執(zhí)行任務(wù),其他判斷都是做“階段過(guò)程資料收集”,無(wú)需關(guān)注
      const continuationCallback = callback(didUserCallbackTimeout);
      currentTime = getCurrentTime();
      if (typeof continuationCallback === 'function') {
        currentTask.callback = continuationCallback;
        if (enableProfiling) {
          markTaskYield(currentTask, currentTime);
        }
        advanceTimers(currentTime);
        return true;
      } else {
        if (enableProfiling) {
          markTaskCompleted(currentTask, currentTime);
          currentTask.isQueued = false;
        }
        if (currentTask === peek(taskQueue)) {
          pop(taskQueue);
        }
        advanceTimers(currentTime);
      }
    } else {
      pop(taskQueue);
    }
    // 執(zhí)行完,再?gòu)?taskQueue 中取出一個(gè)任務(wù)
    currentTask = peek(taskQueue);
    if (enableAlwaysYieldScheduler) {
      if (currentTask === null || currentTask.expirationTime > currentTime) {
        break;
      }
    }
  }
  // 如果任務(wù)不為空,那么還有更多的任務(wù),hasMoreTask 為 true
  if (currentTask !== null) {
    return true;
  } else {
    // taskQueue 這個(gè)隊(duì)列空了,那么我們就從 timerQueue 里面去看延時(shí)任務(wù)
    const firstTimer = peek(timerQueue);
    if (firstTimer !== null) {
      requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
    }
    // 沒(méi)有進(jìn)入上面的 if,說(shuō)明 timerQueue 里面的任務(wù)也完了,返回 false,外部的 hasMoreWork 拿到的就也是 false
    return false;
  }
}

任務(wù)是否可以被打斷?

shouldYieldToHost()

如果返回 true:

  • 當(dāng)前宏任務(wù)結(jié)束
  • 重新發(fā) MessageChannel
  • 瀏覽器可以渲染

六、shouldYieldToHost —— 時(shí)間片控制核心

源碼核心:

function shouldYieldToHost() {
  const timeElapsed = getCurrentTime() - startTime;

  if (timeElapsed < frameInterval) {
    return false;
  }

  return true;
}

其中:

frameInterval = 5ms

注意:

React 不等 16ms 一整幀

而是:

每 5ms 檢查一次

為什么?

  • 預(yù)留給瀏覽器 layout + paint
  • 預(yù)留給輸入事件

七、advanceTimers —— 延遲任務(wù)晉升機(jī)制

每次 workLoop 結(jié)束后,會(huì)調(diào)用 advanceTimers(currentTime); 。

它會(huì):

  • 檢查 timerQueue
  • 把到時(shí)間的任務(wù)移動(dòng)到 taskQueue
function advanceTimers(currentTime) {
  // 取出 startTime <= currentTime 的 timer
  let timer = peek(timerQueue);
  while (timer !== null && timer.startTime <= currentTime) {
    pop(timerQueue);
    timer.sortIndex = timer.expirationTime;
    push(taskQueue, timer);
    timer = peek(timerQueue);
  }
}

這保證:延遲任務(wù)不會(huì)餓死

八、Scheduler 與 Fiber 的關(guān)系

Scheduler 不知道 Fiber。

它只負(fù)責(zé):“什么時(shí)候調(diào)用 callback”

而 callback 通常是:

performConcurrentWorkOnRoot

那里面才是:

  • beginWork
  • completeWork
  • commitRoot

九、任務(wù)拆分的思路來(lái)源

假設(shè)有這樣一段源碼:

unstable_scheduleCallback(NormalPriority, () => {
  heavyWork(); // 10ms
});

如果 heavyWork() 是同步執(zhí)行 10ms:,Scheduler ?無(wú)法中斷它,?因?yàn)?JS 是單線程的,函數(shù)執(zhí)行過(guò)程中無(wú)法被搶占。

來(lái)看源碼核心邏輯:

const continuation = callback();

if (typeof continuation === 'function') {
  currentTask.callback = continuation;
} else {
  pop(taskQueue);
}

如果 callback 返回一個(gè)函數(shù),Scheduler 會(huì)把它當(dāng)成“任務(wù)的下一段”。

舉一個(gè)最小可理解示例:

// 假設(shè)這是一個(gè)“大”任務(wù)
function createBigTask(total) {
  let i = 0;

  function work() {
    while (i < total) {
      console.log(i++);
      
      if (shouldStopManually()) {
        return work; // ?? 返回自身,表示還有后續(xù)
      }
    }

    return null; // 完成
  }

  return work;
}

調(diào)度:

unstable_scheduleCallback(
  NormalPriority,
  createBigTask(1000)
);

執(zhí)行:

workLoop()
  ↓
執(zhí)行 work()
  ↓
執(zhí)行到一部分
  ↓
返回 work (continuation)
  ↓
Scheduler 保存 callback = work
  ↓
shouldYieldToHost() 為 true
  ↓
break
  ↓
下一幀繼續(xù)執(zhí)行

在 React 里,被拆分的任務(wù)不是“普通函數(shù)”,而是:performConcurrentWorkOnRoot。

它內(nèi)部會(huì)調(diào)用:workLoopConcurrent() 。

核心邏輯(簡(jiǎn)化版):

while (
  workInProgress !== null &&
  !shouldYield()
) {
  performUnitOfWork(workInProgress);
}

performUnitOfWork 只做一個(gè) Fiber 節(jié)點(diǎn):

function performUnitOfWork(unit) {
  const next = beginWork(unit);

  if (next === null) {
    completeUnitOfWork(unit);
  }

  return next;
}

也就是說(shuō):React 把整棵 Fiber 樹(shù)拆成一個(gè)個(gè)“節(jié)點(diǎn)單位”/“任務(wù)切片”。

更形象的可以表示為:

一個(gè)組件樹(shù):

App
 ├─ Header
 ├─ Content
 │    ├─ List
 │    └─ Sidebar
 └─ Footer

會(huì)被拆成:

performUnitOfWork(App)
performUnitOfWork(Header)
performUnitOfWork(Content)
performUnitOfWork(List)
performUnitOfWork(Sidebar)
performUnitOfWork(Footer)

每個(gè) Fiber 節(jié)點(diǎn)就是一個(gè)小任務(wù)。

回到 Scheduler 這段判斷:

if (
  currentTask.expirationTime > currentTime &&
  shouldYieldToHost()
) {
  break;
}

當(dāng)時(shí)間片用完時(shí):break 。

此時(shí):

  • workLoop 停止
  • 任務(wù)還沒(méi)完成
  • currentTask.callback 仍然是 performConcurrentWorkOnRoot

下一幀:

MessageChannel
  ↓
performWorkUntilDeadline
  ↓
flushWork
  ↓
workLoop
  ↓
繼續(xù)執(zhí)行 performConcurrentWorkOnRoot

延時(shí)任務(wù)并不會(huì)立刻進(jìn)入 taskQueue,而是先進(jìn)入 timerQueue,等待被“喚醒”然后再調(diào)度。

十、完整調(diào)度流程

下面是一個(gè)完整的流程圖:

unstable_scheduleCallback()
            ↓
            是否延時(shí)? (startTime > now)
           / \
        是     否
         ↓      ↓
  push(timerQueue) push(taskQueue)
         ↓      ↓
requestHostTimeout(requestHostCallback)
         ↓      ↓
       等待 Timer   requestHostCallback
         ↓              ↓
timeout 到時(shí)           MessageChannel
  ↓                   ↓
handleTimeout       performWorkUntilDeadline
  ↓                   ↓
advanceTimers         flushWork
  ↓                  ↓
timerQueue → taskQueue
                    ↓
                 workLoop
                    ↓
            shouldYieldToHost?
                    ↓
       是                      否
 notifyBrowserPaint          執(zhí)行 Callback
                             ↓
                       callback 返回 continuation?
                             ↓
            是                               否
    更新 Task.callback                      pop(taskQueue)
                             ↓
                     可能再次調(diào)度

示例理解

示例 1:普通任務(wù)(正常進(jìn)入隊(duì)列)

unstable_scheduleCallback(
  NormalPriority,
  () => console.log("normal")
);

步驟:

  1. now <= startTime (0 delay)
  2. 放入 taskQueue
  3. requestHostCallback(flushWork)
  4. MessageChannel 觸發(fā) performWorkUntilDeadline
  5. flushWork → workLoop
  6. 執(zhí)行 task
  7. taskQueue 空 → 調(diào)度結(jié)束

示例 2:延時(shí)任務(wù)(未來(lái)才執(zhí)行)

unstable_scheduleCallback(
  NormalPriority,
  () => console.log("delayed"),
  { delay: 1000 }
);

步驟:

t=0
↓
startTime = now + 1000
push(timerQueue)
requestHostTimeout(handleTimeout, 1000)

1s 后:

handleTimeout 被 setTimeout 調(diào)用

advanceTimers
  → 取出 timerQueue 里所有 startTime <= 1s 的任務(wù)
  → 推到 taskQueue
taskQueue 變非空

requestHostCallback(flushWork)

MessageChannel 回調(diào)

flushWork → workLoop → task 執(zhí)行

示例 3:延時(shí)任務(wù)到了中間又被打斷

unstable_scheduleCallback(
  NormalPriority,
  step1,
  { delay: 1000 }
);

function step1() {
  console.log("step1");
  return step2;
}

function step2() {
  console.log("step2");
}

執(zhí)行過(guò)程:

t=0 → timerQueue 入隊(duì)
t=1000  → handleTimeout
  → advanceTimers → taskQueue

MessageChannel

workLoop 執(zhí)行 step1 延時(shí)任務(wù)

step1 返回 continuation step2 延時(shí)任務(wù)

此時(shí)
  workLoop 檢查 shouldYieldToHost
  如果 time片到 → 中斷
  → callback (continuation) 留在 taskQueue
  → requestHostCallback 執(zhí)行普通任務(wù)
下次繼續(xù)執(zhí)行 step2 延時(shí)任務(wù)

設(shè)計(jì)哲學(xué)

① 延時(shí)任務(wù)不能搶占瀏覽器渲染

如果立即調(diào)度:

setTimeout(() => {}), Promise.then(...)

React 可能會(huì)阻塞頁(yè)面渲染

所以必須分開(kāi):

先 timerQueue 等待
再 taskQueue 才跑

② 延時(shí)任務(wù)按照優(yōu)先級(jí)

即使 delay 到了:

expirationTime = startTime + timeout

如果更高優(yōu)先級(jí)任務(wù)進(jìn)入 taskQueue:

React 會(huì)先執(zhí)行高優(yōu)先級(jí)的。

delay 控制什么時(shí)候進(jìn)入 taskQueue,而 expirationTime 控制進(jìn)入 taskQueue 之后的優(yōu)先級(jí)排序。

③ extendable 繼續(xù)推進(jìn)任務(wù)

一個(gè)任務(wù)返回 continuation 時(shí):

currentTask.callback = continuation;

并且還可能繼續(xù) schedule。

到此這篇關(guān)于深入理解React19中任務(wù)調(diào)度器Scheduler的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)React任務(wù)調(diào)度器Scheduler內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React Hook用法示例詳解(6個(gè)常見(jiàn)hook)

    React Hook用法示例詳解(6個(gè)常見(jiàn)hook)

    這篇文章主要介紹了React Hook用法詳解(6個(gè)常見(jiàn)hook),本文通過(guò)實(shí)例代碼給大家介紹了6個(gè)常見(jiàn)hook,需要的朋友可以參考下
    2021-04-04
  • 詳解使用React進(jìn)行組件庫(kù)開(kāi)發(fā)

    詳解使用React進(jìn)行組件庫(kù)開(kāi)發(fā)

    本篇文章主要介紹了詳解使用React進(jìn)行組件庫(kù)開(kāi)發(fā),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • React Hooks獲取數(shù)據(jù)實(shí)現(xiàn)方法介紹

    React Hooks獲取數(shù)據(jù)實(shí)現(xiàn)方法介紹

    這篇文章主要介紹了react hooks獲取數(shù)據(jù),文中給大家介紹了useState dispatch函數(shù)如何與其使用的Function Component進(jìn)行綁定,實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • 探討JWT身份校驗(yàn)與React-router無(wú)縫集成

    探討JWT身份校驗(yàn)與React-router無(wú)縫集成

    這篇文章主要為大家介紹了JWT身份校驗(yàn)與React-router無(wú)縫集成的探討解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 淺析JS中什么是自定義react數(shù)據(jù)驗(yàn)證組件

    淺析JS中什么是自定義react數(shù)據(jù)驗(yàn)證組件

    我們?cè)谧銮岸吮韱翁峤粫r(shí),經(jīng)常會(huì)遇到要對(duì)表單中的數(shù)據(jù)進(jìn)行校驗(yàn)的問(wèn)題。這篇文章主要介紹了js中什么是自定義react數(shù)據(jù)驗(yàn)證組件,需要的朋友可以參考下
    2018-10-10
  • React生命周期函數(shù)圖解介紹

    React生命周期函數(shù)圖解介紹

    生命周期函數(shù)指在某一時(shí)刻組件會(huì)自動(dòng)調(diào)用并執(zhí)行的函數(shù)。React每個(gè)類組件都包含生命周期方法,以便于在運(yùn)行過(guò)程中特定的階段執(zhí)行這些方法
    2022-11-11
  • 詳解React項(xiàng)目中eslint使用百度風(fēng)格

    詳解React項(xiàng)目中eslint使用百度風(fēng)格

    這篇文章主要介紹了React項(xiàng)目中eslint使用百度風(fēng)格,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • React Native自定義路由管理的深入理解

    React Native自定義路由管理的深入理解

    路由管理的功能主要指的頁(yè)面跳轉(zhuǎn)、goBack、帶參數(shù)跳轉(zhuǎn)等功能,這篇文章主要給大家介紹了關(guān)于React Native自定義路由管理的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • React中組件優(yōu)化的最佳方案分享

    React中組件優(yōu)化的最佳方案分享

    React組件性能優(yōu)化可以減少渲染真實(shí)DOM的頻率,以及減少VD比對(duì)的頻率,本文為大家整理了一些有效的React組件優(yōu)化方法,需要的小伙伴可以參考下
    2023-12-12
  • react編寫可編輯標(biāo)題示例詳解

    react編寫可編輯標(biāo)題示例詳解

    這篇文章主要為大家介紹了react編寫可編輯標(biāo)題示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08

最新評(píng)論

洛扎县| 永兴县| 正阳县| 长宁县| 隆德县| 法库县| 阜新| 绿春县| 武隆县| 凤凰县| 游戏| 鸡泽县| 乌什县| 曲水县| 阜康市| 上犹县| 横山县| 喀喇沁旗| 磴口县| 青龙| 雷州市| 南汇区| 安塞县| 长沙县| 综艺| 高雄市| 尤溪县| 达拉特旗| 华安县| 潼南县| 天门市| 惠东县| 巴东县| 沈阳市| 铁力市| 烟台市| 苏尼特右旗| 新营市| 嘉荫县| 微山县| 锡林郭勒盟|