ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2022-02-21 11:02:26  阅读:193  来源: 互联网

标签:fiber const 一帧 react 任务 源码 react17 执行 空闲


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阶段的设计思想

  • 当发生渲染或者更新操作时,react去创建一系列的任务,任务带有优先级,然后构建workInProgress fiber树链表。
  • 遍历任务链表去执行任务。每一帧帧先执行浏览器的渲染等任务,如果当前帧还有空闲时间,则执行任务,直到当前帧的时间用完。如果当前帧已经没有空闲时间,就等到下一帧的空闲时间再去执行。如果当前帧没有空闲时间但是当前任务链表有任务到期了或者立即基执行任务,那么必须执行的时候就以丢失几帧的代价,执行这些任务。执行完的任务都会被从链表中删除。

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

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有