编程语言
首页 > 编程语言> > react17.x源码解析(3)——fiber树的构建与更新续

react17.x源码解析(3)——fiber树的构建与更新续

作者:互联网

react通过new MessageChannel()创建了消息通道,当发现js线程空闲时,通过postMessage通知scheduler开始调度。然后react接收到调度开始的通知时,就通过performWorkUntilDeadline函数去更新当前帧的结束时间,以及执行任务。从而实现了帧空闲时间的任务调度。

// packages/scheduler/src/forks/SchedulerHostConfig.default.js

// 获取当前设备每帧的时长
forceFrameRate = function(fps) {
  // ...
  if (fps > 0) {
    yieldInterval = Math.floor(1000 / fps);
  } else {
    yieldInterval = 5;
  }
};

// 帧结束前执行任务
const performWorkUntilDeadline = () => {
  if (scheduledHostCallback !== null) {
    const currentTime = getCurrentTime();
    // 更新当前帧的结束时间
    deadline = currentTime + yieldInterval;
    const hasTimeRemaining = true;
    try {
      const hasMoreWork = scheduledHostCallback(
        hasTimeRemaining,
        currentTime,
      );
      // 如果还有调度任务就执行
      if (!hasMoreWork) {
        isMessageLoopRunning = false;
        scheduledHostCallback = null;
      } else {
        // 没有调度任务就通过 postMessage 通知结束
        port.postMessage(null);
      }
    } catch (error) {
      // ..
      throw error;
    }
  } else {
    isMessageLoopRunning = false;
  }
  needsPaint = false;
};

// 通过 MessageChannel 创建消息通道,实现任务调度通知
const channel = new MessageChannel();
const port = channel.port2;
channel.port1.onmessage = performWorkUntilDeadline;

// 通过 postMessage,通知 scheduler 已经开始了帧调度
requestHostCallback = function(callback) {
  scheduledHostCallback = callback;
  if (!isMessageLoopRunning) {
    isMessageLoopRunning = true;
    port.postMessage(null);
  }
};

任务中断

前面说到可中断模式下的workLoop,每次遍历执行performUnitOfWork前会先判断shouYield的值

// packages/react-reconciler/src/ReactFiberWorkLoop.old.js

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

再看一下shouYield的值是如何获取的:

//packages\scheduler\src\SchedulerPostTask.js
export function unstable_shouldYield() {
  return getCurrentTime() >= deadline;
}

getCurrentTime获取的是当前的时间戳,deadline上面讲到了是浏览器每一帧结束的时间戳。也就是说concurrent模式下,react会将这些非同步任务放到浏览器每一帧空闲时间段去执行,若每一帧结束未执行完,则中断当前任务,待到浏览器下一帧空闲再继续执行。

总结react render阶段的设计思想

执行过程中的流程图如下:
image

标签:fiber,const,一帧,react,任务,源码,react17,执行,空闲
来源: https://www.cnblogs.com/huayang1995/p/15917918.html