最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 浅谈React Fiber--比Thread更精密的并发处理机制

    正文概述 掘金(头号前端)   2021-01-30   552

    一、什么是Fiber

    1. Fiber

    2. React Fiber

    直观的感受:claudiopro.github.io/react-fiber…

    3. 为什么Stack reconsiler会导致丢帧

    浅谈React Fiber--比Thread更精密的并发处理机制

    <div>
       <Foo>
          <Bar />
       </Foo>
    </div>
    

    上面的JSX经过编译会变成递归调用的代码,当组件树很深的时候,需要一次性去Diff组件的变化会消耗很长的时间,导致script时间变长。React之前做的优化是类似用 shouldComponentUpdate 来跳过一些组件的Diff。

    二、Fiber优化的思路

    1. 背景

    React的基本架构

    浅谈React Fiber--比Thread更精密的并发处理机制

    react 即 reconsiler(调度者),react-dom则是 renderer 调度者一直都是又 React 本身决定,而 renderer 则可以由社区控制和贡献。如ReactNative、React-dom等等, 而Fiber是属于reconsiler的优化。

    2. Fiber细节

    2.1 生成Fiber节点

    React Element

    当一个模板被传入到 JSX 编译器,最终会生成 React Element 。它其实就是 React 组件的 render 方法返回的实际内容,并不是 HTML

    class ClickCounter {
        //...
        render() {
            return [
                React.createElement(
                    'button',
                    {
                        key: '1',
                        onClick: this.onClick
                    },
                    'Update counter'
                ),
                React.createElement(
                    'span',
                    {
                        key: '2'
                    },
                    this.state.count
                )
            ]
        }
    }
    
    // 这里调用的  React.createElement  方法返回了如下所示的两个数据结构:
    [
        {
            $$typeof: Symbol(react.element),
            type: 'button',
            key: "1",
            props: {
                children: 'Update counter',
                onClick: () => { ... }
            }
        },
        {
            $$typeof: Symbol(react.element),
            type: 'span',
            key: "2",
            props: {
                children: 0
            }
        }
    ]
    

    Fiber Nodes

    fiber 节点就是描述随后要执行工作的一种数据结构,可以类比于调用栈中的帧 ,换而言之,就是一个工作单元。fiber 架构同时还提供了便捷的方式去追踪,调度,暂停,中断协调进程。

    当一个 React Element 第一次被转换为 fiber 节点的时候,React 将会从 React Element 种提取数据子并在createFiberFromTypeAndProps函数中创建一个新的 fiber。随后的更新过程中 React会复用这个创建的 fiber 节点,并将对应 React Element 被改变数据更新到这个 fiber 节点上。React 也会移除一些 fiber节点,例如:当同层级上对应 key属性改变时,或 render 方法返回的 React Element 没有该 fiber 对应的 Element 对象时,该 fiber 就会被删除。

    因为 React 会为每个得到的 React Element 创建 fiber,这些 fiber 节点被连接起来组成 fiber tree。在我们的例子中它是这样的

    浅谈React Fiber--比Thread更精密的并发处理机制

    2.2 分为Reconciliation 阶段和Commit 阶段

    在React Fiber中,一次更新过程会分成多个分片完成,所以完全有可能一个更新任务还没有完成,就被另一个更高优先级的更新过程打断,这时候,优先级高的更新任务会优先处理完,而低优先级更新任务所做的工作则会完全作废,然后等待机会重头再来

    因为一个更新过程可能被打断,所以React Fiber一个更新过程被分为两个阶段(Phase):第一个阶段Reconciliation Phase和第二阶段Commit Phase。

    在第一阶段Reconciliation Phase,React Fiber会找出需要更新哪些DOM,这个阶段是可以被打断的;但是到了第二阶段Commit Phase,那就一鼓作气把DOM更新完,绝不会被打断。

    requestIdleCallback

    var  = .requestIdleCallback([, ])
    
    • callback: () :回调即空闲时需要执行的任务,接收一个对象作为入参。其中 [IdleDeadline](https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline) 对象包含:

      • didTimeout ,布尔值,表示任务是否超时,结合 timeRemaining 使用

      • timeRemaining() ,表示当前帧剩余的时间,也可理解为留给任务的时间还有多少

    • options :目前 options 只有一个参数

      • timeout :如果指定了timeout并具有一个正值,并且尚未通过超时毫秒数调用回调,那么回调会在下一次空闲时期被强制执行,尽管这样很可能会对性能造成负面影响。
    • cancelIdleCallback

    React实现的requestIdleCallback

    1. 由于 requestIdleCallback 兼容性不是特别好

    浅谈React Fiber--比Thread更精密的并发处理机制

    1. 且只能一秒调用回调 20 次

    无法满足实际的需求,React自己实现了一个版本.

    实现 requestIdleCallback 函数的核心是:如何多次在浏览器空闲时且是渲染后才调用回调方法?

    使用requestAnimationFrame 和 setTimeout完成多次执行

    requestAnimationFrame 的回调方法会在每次重绘前执行,另外它还存在一个瑕疵:页面处于后台时该回调函数不会执行,因此我们需要对于这种情况做个补救措施

    rAFID = requestAnimationFrame(function(timestamp) {
      // cancel the setTimeout
      localClearTimeout(rAFTimeoutID);
      callback(timestamp);
    });
    rAFTimeoutID = setTimeout(function() {
      // 定时 100 毫秒是算是一个最佳实践
      localCancelAnimationFrame(rAFID);
      callback(getCurrentTime());
    }, 100);
    

    计算当前帧是否空闲

    简单来说就是假设当前时间为 5000,浏览器支持 60 帧,那么 1 帧近似 16 毫秒,那么就会计算出下一帧时间为 5016,判断时间是否小于5016.

    渲染后执行任务

    在渲染以后只有宏任务是最先会被执行的,因此宏任务就是我们实现这一步的操作了。

    但是生成一个宏任务有很多种方式并且各自也有优先级,那么为了最快地执行任务,我们肯定得选择优先级高的方式。在这里我们选择了 MessageChannel 来完成这个任务,不选择 setImmediate 的原因是因为兼容性太差。

    2.3 Reconciliation的调度过程

    • 首先每个任务都会有各自的优先级,高优先级的任务会打断低优先级任务

    • 在调度之前,判断当前任务是否过期,过期的话无须调度,直接生成一个任务,这样就能在渲染后马上执行过期任务了

    • 如果任务没有过期,就通过 requestAnimationFrame 启动定时器,在重绘前调用回调方法在回调方法中我们首先需要计算每一帧的时间以及下一帧的时间,然后创建一个宏任务去执行。

    • 宏任务会在渲染后被调用,在这个过程中我们首先需要去判断当前时间是否小于下一帧时间。如果小于的话就代表我们尚有空余时间去执行任务;如果大于的话就代表当前帧已经没有空闲时间了,这时候我们需要去判断是否有任务过期,过期的话不管三七二十一还是得去执行这个任务。如果没有过期的话,那就只能把这个任务丢到下一帧看能不能执行了。

    3. 整体流程

    1. 初始化渲染,从React Element生成对应的Fiber树

    2. 进行setState操作,触发更新

    3. 创建workInProgress副本,进入Reconciliation执行对应的render更新。

    4. 记录有副作用的fiber节点,放入一个队列

    5. 完成Reconciliation,进入Commit阶段,取出有副作用的fiber节点,通过fiber节点的nextEffect属性访问有副作用的节点,进行更新

    4. 关于生命周期

    浅谈React Fiber--比Thread更精密的并发处理机制

    4.1 UNSAFE的声明周期

    • [UNSAFE_]componentWillMount (deprecated)

    • [UNSAFE_]componentWillReceiveProps (deprecated)

    • getDerivedStateFromProps

    • shouldComponentUpdate

    • [UNSAFE_]componentWillUpdate (deprecated)

    4.2 componentWillReceiveProps和getDerivedStateFromProps

    willXXX可以让用户任意操作DOM。 操作DOM会可能reflow,这是官方不愿意看到的。于是官方推出了getDerivedStateFromProps,让你在render时设置新state,你主要返回一个新对象,它就主动帮你setState。 由于这是一个静态方法,你不能操作instance,这就阻止了你多次操作setState。也没有refs,你也没有机会操作DOM了。这样一来,getDerivedStateFromProps的逻辑应该会很简单,这样就不会出错,不会出错,就不会打断DFS过程。

    参考

    • React Components, Elements, and Instances

    • reactjs.org/docs/design…

    • zhuanlan.zhihu.com/p/37095662

    • segmentfault.com/a/119000002…

    • segmentfault.com/a/119000001…


    起源地下载网 » 浅谈React Fiber--比Thread更精密的并发处理机制

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元