深入React Fiber

吐槽君 分类:javascript

深入了解下React Fiber

原文:blog.logrocket.com/deep-dive-i…


本文核心

  • 当react遍历tree的时候,在execStack里面干这件事
  • 当updates到来的时候,他们在eventQueue里干这件事(调用setState)
  • 只有当execStack为空了,eventQueue里的updates被得到执行(被延迟的setState在这里被真正执行)

Fiber就是彻底重构了上述Stack的流程,创建了virtual stack,里面加入了puase(暂停),resume(恢复),abort(终止)等

简单来说,之前React创建不可修改的objects的tree,通过递归遍历来处理
现在,React创建一个可修改的fiber nodes的tree,fiber node高效的来处理state,props,Dom Element等

因为fiber nodes可以改变所以不需要recreate,只需要cloen然后update
__同时不需要进行递归遍历,而是创建单链表然后parent-first和depth-first遍历


开始

"Stack" reconciler (Last-in,first out)

ReactDOM.render(<App />, document.getElementById('root'))开始。

  • <App/>是个啥?
    • <App/>就是虚拟dom,描述了dom的类型,属性,子元素等信息。

React里面的Element有两种

  • Dom Element <div></div>
  • Component Element <Button></Button>

这两个类型都是简单的object,都是虚拟dom,告诉React应该渲染什么

React如何处理Component Element

<Form>
  <Button>
    Submit
  </Button>
</Form>
 
  • React会根据Form,Button以及他们相应的props询问他们渲染了什么东西?
  • 如果Form是一个function component,React就会调用render获取其渲染的内容
const Form = (props) => {
  return(
    <div className="form">
      {props.form}
    </div>
  )
}
 
  • React会一直重复下去,直到获取所有Component Elment的渲染内容
  • 这个获取Dom Element的过程就是我们熟知的reconciliation
  • reconciliation结束后,React就可以直到了Dom的结构,
  • 也就是说ReactDOM.render或setState都会触发reconciliation;在setState的时候,通过new state tree和rendered tree的diff,来最小粒度的更新current tree

如果setState立即被执行就很可能发生掉帧

现在的设备fps一般在60fps,也就是1/60≈16ms每帧,假如React的渲染时间大于了16ms,那么这次渲染到了16ms的时候并没有拿到结果,这个渲染就不会被正常的渲染出来,这就是掉帧,掉帧就引起了卡顿。然而现实中我们只有10ms的时间来完成渲染,因为浏览器还要做其他的事情。

Fiber是如何工作的

Fiber的4个目标

  • 给不同类型的渲染分配不同的优先级
  • 暂停渲染,之后再回来
  • 终止渲染,如果不再需要了
  • 重复利用已经计算好的渲染

Fiber的挑战在于JavaScript引擎的工作原理,如何才能多线程的工作。

先了解下JavaScript引擎的工作原理(执行环境)

  • JavaScript引擎开始的时候创建全局的执行环境(window in browser, global in node) execStack: [globalExecContext]
function a() {
  console.log("i am a")
  b()
}

function b() {
  console.log("i am b")
}

a()
 
  • 执行a的时候,创建a的执行环境并push到全局中 execStack: [aExecContext, globalExecContext]
  • 因为b在a中执行,也创建b的执行环境并push到全局中 {execStack: [bExecContext, aExecContext, globalExecContext]}
  • 异步的时候有个eventQueue {execStack: [aExecContext, globalExecContext], eventQueue: {http}
  • JavaScript引擎只会在execStack为空或者只有globalExecContext的时候才会去遍历eventQueue

回到React的Stack Reconciler

  • 当react遍历tree的时候,在execStack里面干这件事
  • 当updates到来的时候,他们在eventQueue里干这件事(调用setState)
  • 只有当execStack为空了,eventQueue里的updates被得到执行(被延迟的setState在这里被真正执行)

Fiber到底干了啥

Fiber就是彻底重构了上述Stack的流程,创建了virtual stack,里面加入了puase(暂停),resume(恢复),abort(终止)等

回复

我来回复
  • 暂无回复内容