道招

React执行调度流程梳理笔记

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

React执行调度流程梳理笔记

触发更新

我们最常见的触发更新的方式就是更新state了,可以分别从类组件和函数组件看看这时会发生什么。

类组件之 setState:

当触发setState本质上是调用enqueueSetState

enqueueSetState(inst,payload,callback){
    const update = createUpdate(eventTime, lane);
    enqueueUpdate(fiber, update, lane);
    const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
}
函数组件之 useState

再看一下 hooks 的useState

function dispatchAction(fiber, queue, action) {
    var lane = requestUpdateLane(fiber);
    scheduleUpdateOnFiber(fiber, lane, eventTime);
}

可以看出来useStatesetState最后都是调用scheduleUpdateOnFiber方法。

看看scheduleUpdateOnFiber方法的原理吧

export function scheduleUpdateOnFiber(fiber,lane,eventTime){
    if (lane === SyncLane) {
        if (
            (executionContext & LegacyUnbatchedContext) !== NoContext && // unbatch 情况,比如初始化
            (executionContext & (RenderContext | CommitContext)) === NoContext) {
            /* 开始同步更新,进入到 workloop 流程 */
            `performSyncWorkOnRoot`
            2. 进入调度(root);
         }else{
               /* 进入调度,把任务放入调度中 */
               ensureRootIsScheduled(root, eventTime);
               if (executionContext === NoContext) {
                   /* 当前的执行任务类型为 NoContext ,说明当前任务是非可控的,那么会调用 flushSyncCallbackQueue 方法。 */
                   flushSyncCallbackQueue();
               }
         }
    }
}

可以看主要分两类

  1. 直接触发performSyncWorkOnRoot,接下来就可以进入调和阶段performSyncWorkOnRoot了。
  2. 进入调度阶段ensureRootIsScheduled,但是里面部分场景会直接触发flushSyncCallbackQueue 2.1 非可控任务:比如是在延时器(timer)队列或者是微任务队列(microtask) 2.2 空闲期的同步任务:避免出现在浏览器空闲状态下发生一次 state 更新,但还需要等到下一次空闲帧才执行

进入调度阶段ensureRootIsScheduled是做什么呢?

function ensureRootIsScheduled(root,currentTime){
    /* 计算一下执行更新的优先级 */
    var newCallbackPriority = returnNextLanesPriority();
    /* 当前 root 上存在的更新优先级 */
    const existingCallbackPriority = root.callbackPriority;
    /* 如果两者相等,那么说明是在一次更新中,那么将退出 */
    if(existingCallbackPriority === newCallbackPriority){
        return 
    }
    if (newCallbackPriority === SyncLanePriority) {
        /* 在正常情况下,会直接进入到调度任务中。 */
        newCallbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));
    }else{
        /* 这里先忽略 */
    }
    /* 给当前 root 的更新优先级,绑定到最新的优先级  */
    root.callbackPriority = newCallbackPriority;
}

ensureRootIsScheduled主要做的事情有:

  • 首先会计算最新的调度更新优先级 newCallbackPriority,接下来获取当前 root 上的 callbackPriority 判断两者是否相等。如果两者相等,那么将直接退出不会进入到调度中。
  • 如果不想等那么会真正的进入调度任务 scheduleSyncCallback 中。注意的是放入调度中的函数就是调和流程的入口函数performSyncWorkOnRoot
  • 函数最后会将 newCallbackPriority 赋值给 callbackPriority。

那么如果在正常模式下(非异步)一次更新中触发了多次setState 或者useState,那么第一个setState进入到ensureRootIsScheduled就会有 root.callbackPriority = newCallbackPriority,那么接下来如果还有setState或(useState),那么就会退出,将不进入调度任务中,原来这才是批量更新的原理,多次触发更新只有第一次会进入到调度中。

总结

不管是直接执行还是进入调度,都是对调和流程的入口函数performSyncWorkOnRoot的处理,区别只不过是何时执行的时机而已,因为最终都会以此进入调和流程。

参考自《React 进阶实践指南之原理篇-更新流程:进入调度任务》

更新时间:
上一篇:amh.sh免费泛域名https证书 自动续期下一篇:Jetbrains旗下IDEA系列产品将于2022.10.1起涨价,最多一次性购买三年

相关文章

改造富文本编辑器wangEditor成react组件

我们知道wangEditor常用的功能是editor实例的 txt.html() 和 txt.text() 方法,尤其是 txt.html() 方法,这是一个类似与jQuery常用的那种get和se 阅读更多…

转译:使用react hooks优化回调函数在组件间的传递,useState,useReducer?

我们先看一下使用 useState hooks写的todoList组件,里面我们需要层层传递回调函数。 import React, { useState } from "react& 阅读更多…

React router用hooks读取routeName、根据routeName跳转

在迁移Vue至React的过程中遇到了一些路由相关的问题,在Vue项目中经常会使用routeName,毕竟使用path太长了,也记不住,我自己看了看React router也没有发现routeNam 阅读更多…

项目Vue转成React hooks可能存在的问题--急需类似setState回调

假设在Vue中有如下三个方法,并且初始时 this.a = ‘a’; this.b = ‘b’; funA() { this.a = '1221&#03 阅读更多…

react router页面跳转二次确认弹框及样式、业务逻辑自定义

我们在编辑页面时如果需要跳走通常会需要给用户提示,react router本身已经给了我们这样的功能,我们先看看怎么使用。 初见二次确认弹框 // App.jsx const App = 阅读更多…

邮箱收件人组件成长历程(二)(React hooks升级版)

记得自己之前写过一篇 《邮箱收件人组件(vue版)成长历程(一)》 记得当时里面写到了自己使用的是可编辑div来进行输入的,同时提到 当时出于挑战自己和青铜的倔强,想试着换个方案,完全使用可编辑di 阅读更多…

关注道招网公众帐号
友情链接
消息推送
道招网关注互联网,分享IT资讯,前沿科技、编程技术,是否允许文章更新后推送通知消息。
允许
不用了