zoukankan      html  css  js  c++  java
  • Fiber异步调和机制

    缘起

    React虚拟DOM的调和渲染可以简单粗暴的递归,但是这个过程是同步的,如果需要处理的节点过多,可能会阻塞用户输入和动画播放,布局等造成卡顿,Fiber是16.x引入的新特性,用处是将同步的调和变成异步的。

    1. 简单概述

    它是React16之后新加入的一种异步VDom调和机制(当前默认没有开启这种异步模式),它把diff过程分解为多个可中断的任务,像一个链表结构,任务之间可以被优先级更高的动画,用户事件打断,让浏览器运行得更浏览畅,不容易出现卡顿现象。

    React15时,整个渲染逻辑是同步的,采用递归方式调用组件的生命周期函数和diff算法,React16之后把diff过程分解成多个小的可打断的时间片,中间使用window.requestIdleCallback(chrome支持,其他浏览器需要模拟类似行为)这个实验性的API解决任务调度的问题,让浏览器在空闲时才计算diff并渲染。

    requestIdleCallback来进行任务调度,它进行任务调度的思想是将任务拆分成多个小任务,requestIdleCallback里面不断的把小任务拿出来执行,当所有任务都执行完或者超时了就结束本次执行,同时要注册下次执行。

    Fibe的思想总结来说,就是把一个大的diff任务分成很多小片,当分配给这个小片的时间用尽的时候,就把JS渲染进程的控制区交出去,让浏览器去检查有没有优先级更高的任务,有就做这个新任务,没有就继续做原来的任务,这种方式被叫做异步渲染(Async Rendering)。

    所以用原来VDom这个单一的大对象就不好做暂停继续操作,所以引入了fiber这个新的可中断可恢复的数据结构,那fiber结构大致是什么样的?

    • fiber节点对象,有childsibing属性,指向第一个子节点和相邻的兄弟节点,return属性指向其父节点,外形上构成了一个fiber树,fiber树本质上是一个链表结构。
    • 每个fiber(当前fiber可以称为current)有一个属性alternate,开始时指向一个自己的clone体,update的变化会先更新到alternate上,当更新完毕,alternate替换current
    • fiber tree是根据vDOM tree构造出来的,他们的树结构一模一样,只是节点携带的信息有差异,工作循环中,每次处理一个fiber,处理完可以中断/挂起整个工作循环。

    2. 基本原理

    React 框架内部的运作可以分为 3 层

    • Virtual DOM 层,描述页面长什么样。
    • Reconciler 层,负责调用组件生命周期方法,进行 Diff 运算等。
    • Renderer 层,根据不同的平台,渲染出相应的页面,比较常见的是 ReactDOM 和 ReactNative。

    Fiber改动最大的当属 Reconciler 层了,React 团队也给它起了个新的名字,叫Fiber Reconciler(调和),之前叫Stack Reconfciler

    Fiber Reconciler 在执行过程中,会分为 2 个阶段

    • 阶段一,生成 Fiber 树,得出需要更新的节点信息。这一步是一个渐进的过程,可以被打断。
    • 阶段二,将需要更新的节点批量更新,这个过程不能被打断。

    阶段一可被打断,让优先级更高的任务先执行,从框架层面大大降低了页面掉帧的概率,当然被打断时,fiber会记录很多中间状态,会记录当前执行的位置,哪些节点已经完成diff计算了,下一次从哪里开始等。

    在render函数中创建的React Element树在第一次渲染的时候会创建一颗结构一模一样的Fiber节点树。不同的React Element类型对应不同的Fiber节点类型。一个React Element的工作就由它对应的Fiber节点来负责。

    一个React Element可以对应不止一个Fiber,因为Fiber在update的时候,会从原来的Fiber(我们称为current)clone出一个新的Fiber(我们称为alternate)。两个Fiber diff出的变化(side effect)记录在alternate上,所以一个组件在更新时最多会有两个Fiber与其对应,在更新结束后alternate会取代之前的current的成为新的current节点。

    3. Fiber的基本规则

    更新任务分成两个阶段,Reconciliation Phase和Commit Phase。

    Reconciliation Phase的任务做的事情是,找出要做的更新工作(Diff Fiber Tree),就是一个计算阶段,计算结果可以被缓存,也就可以被打断;

    Commmit Phase 需要提交所有更新并渲染,为了防止页面抖动,被设置为不能被打断。

    4. 平时编程需要注意些什么?

    componentWillMount, componentWillReceiveProps,shouldComponentUpdate(它没啥大问题,不会产生副作用), componentWillUpdate 几个生命周期方法不再安全,由于任务执行过程可以被打断,这几个生命周期可能会执行多次,如果它们包含副作用(比如aJax),会有意想不到的bug,React16.3团队提供了一些新的周期函数,建议用新的周期函数做替待 when you have to do something with these life functions。

     static getDerivedStateFromProps(props, state) {
        // 代替componentWillReceiveProps
      }
     //新的静态 getDerivedStateFromProps 生命周期方法在组件实例化之后以及重新渲染之前调用。它可以返回一个对象来更新 state,或者返回 null 来表示新的 props 不需要任何 state 的更新。
     getSnapshotBeforeUpdate(prevProps, prevState) // 它代替componentWillUpdate。建议如果使用以上方法,尽量用纯函数,避免以后采坑
  • 相关阅读:
    Ubuntu设置默认编辑器
    Java基础学习之(15)
    Java基础学习之(9)--java的常用类
    Java基础学习之(11)--异常处理
    Java基础学习之(10)--接口
    Java基础学习之(8)--多态和抽象类
    Java基础学习之(7)--Object类
    Java基础学习之(6)--继承、访问权限、重写
    dubbo-整合springboot、基于注解的简单实例
    java安全框架之Permission学习笔记
  • 原文地址:https://www.cnblogs.com/roy1/p/13872969.html
Copyright © 2011-2022 走看看