React Fiber学习小结

前天在油管上看了大神的一个关于js优化的分享,佩服的五体投地。可是视频又过短了,就20来分钟,有点意犹未尽的意思,还好视频结尾放了几篇大神写的关于react fiber的文章,因此赶忙找来学习了一下。html

Fiber

fiber node是react内部用来表明一些须要完成的工做的一种数据结构,每个react element都会对应一个fiber node。以前react15里的vdom tree如今就变成了一个fiber tree,每个fiber node都保存着指向其sibling, child 和 parent的指针。因此fiber tree大概就是一个双向的linked list吧。node

为啥搞fiber

既然已经有了vdom tree,为啥又搞了这么个fiber tree?react

我没细读过源码,不过从官方文档,大概由于vdom tree的遍历采用了递归的写法。 递归一旦开始,在结束以前,都不受控了。也就是说,若是react触发一次update,那么在update完成以前,浏览器主线程啥都干不了。。 若是这个update耗时比较久,那就会形成卡顿。git

因此最大的问题就是遍历起来不受控了。。想要控制咋办?拿while来改写递归呗。因此react组里的大佬们就搞出了这么个"fiber linked list"。github

fiber工做流程

fiber的工做大概能够分为两个阶段: 1. render 2. commit浏览器

render phase

在第一次mount以后,react会为每个渲染的react element都创建一个fiber node,并组成一颗树(current)。当更新触发的时候,react会创建另一颗树(workInProgress),全部的updates都会反映在这颗树上。而且两颗树之间的节点都有一个alternate的属性,指向本身在另外一颗树上的映射。在这个阶段,react会在workInProgress的节点上更新state和props,但并不会作任何带有side effect的操做(留给commit阶段),这里react只会给每一个节点记录在commit阶段到底应该作些啥操做,这个信息保存在effectTag字段上。数据结构

除了构建workInProgress树以外,为了提升性能,react 还会维护一个effect list。就是用全部有sideeffect操做的节点构建一个linkedlist。 等真的到了要执行这些操做的时候,直接扫这个list就行了,而不用去遍历整个树。dom

除了上面的工做,render phase还会调用如下的函数:异步

  1. [UNSAFE_]componentWillMount (deprecated)
  2. [UNSAFE_]componentWillReceiveProps (deprecated)
  3. getDerivedStateFromProps
  4. shouldComponentUpdate
  5. [UNSAFE_]componentWillUpdate (deprecated)
  6. render

commit phase

render阶段生成了current树,workInProgress树和effect list,接下来就进入到commit 阶段。async

在commit阶段,react会直接遍历effect list,完成每一个节点的操做。在全部节点完成以后,用workInProgress树来替换current树,旧的current树就能够被垃圾回收了。

在commit阶段,除了完成每一个节点的工做外,还会跑这几个函数:

  1. 对于有snapShop标签的node,调用getSnapshotBeforeUpdate
  2. 对于有Deletion标签的node,调用componentWillUnmount
  3. 对于有Placement标签的node,调用componentDidMount
  4. 对于有Update标签的node,调用componentDidUpdate

那么问题来了, 为啥react要大费周章的搞这么两个阶段呢?

缘由是在render phase阶段,全部操做能够是异步的。 react会把遍历整颗树的任务切成小任务,放在requestIdleCallback里面来执行。 可是每次在暂停以后,下一次再继续的时候,有可能会放弃掉以前作的全部任务重头来过(这个的缘由不是特别清楚,多是在两个任务以前,某个状态改变了,以前的任务可能已经失效了?),因此全部会产生反作用的操做都不能放在这个阶段执行。 react 16.3把不少原来经常使用的生命周期标记为unsafe也是这个道理。就是由于react的大佬们发现使用者老在这些生命周期函数写一些带反作用的逻辑。这种写法在fiber的体系下问题就很大(可能会被执行屡次), 官方的这篇文章把这个事情也说的特别清楚了。

而commit phase则相反,全部的操做都会一口气作完(同步)。因此啊,在commit phase调用的生命周期里面,最好仍是不要作过重的活为好。。

参考文献

React Fiber Architecture The how and why on React’s usage of linked list in Fiber to walk the component’s tree

Inside Fiber: in-depth overview of the new reconciliation algorithm in React

Update on Async Rendering

相关文章
相关标签/搜索