Fiber初探

110 阅读2分钟

Fiber

Fiber 是 React 16\color{#FF3030}{16} 对 React 核心算法的一次重写。

Fiber 会使原本 同步的渲染>异步\color{#FF3030}{同步的渲染 >异步} 的。

同步渲染的递归调用栈是非常深, 不可打断\color{#FF3030}{不可打断} , 无法处理用户交互的状态,面临卡顿甚至卡死的风险。

Fiber 会将一个大的更新任务拆解为许多个小任务。每当执行完一个小任务,渲染线程都会把主线程交回去\color{#FF3030}{主线程交回去},看看有没有优先级更高的工作要处理。

根据“能否被打断”这一标准,React 16 的生命周期被划分为了rendercommit\color{#FF3030}{render 和 commit} 两个阶段, render 阶段在执行过程中允许被打断,而 commit 阶段则总是同步执行的。

render 阶段的操作对用户来说其实是“不可见”的,而 commit 阶段的操作则涉及真实 DOM 的渲染

我们再来看看 React 16 打算废弃\color{#FF3030}{废弃}的是哪些生命周期:

componentWillMount;
componentWillUpdate;
componentWillReceiveProps。

这些生命周期的共性,就是它们都处于 render 阶段,都可能重复被执行\color{#FF3030}{重复被执行},而且由于这些 API 常年被滥用,它们在重复执行的过程中都存在着不可小觑的风险。

骚操作, 在“componentWill”开头的生命周期里,你习惯于做的事情可能包括但不限于:

setState();
fetch 发起异步请求;
操作真实 DOM。

这些操作的问题(或不必要性)包括但不限于以下 3 点:

(1)完全可以转移到其他生命周期(尤其是 componentDidxxx)里去做。

比如在 componentWillMount 里发起异步请求,异步请求再怎么快也快不过(React 15 下)同步的生命周期。componentWillMount 结束后,render 会迅速地被触发,所以说首次渲染依然会在数据返回之前\color{#FF3030}{首次渲染依然会在数据返回之前}执行。

(2)在 Fiber 带来的异步渲染机制下,可能会导致非常严重的 Bug。

比如说,这件商品单价只要 10 块钱,用户也只点击了一次付款。但实际却可能因为 componentWillxxx 被打断+重启多次\color{#FF3030}{被打断 + 重启多次}而多次调用付款接口,最终付了 50 块钱;

又或者你可能会习惯在 componentWillReceiveProps 里操作 DOM(比如说删除符合某个特征的元素),那么 componentWillReceiveProps 若是执行了两次\color{#FF3030}{执行了两次},你可能就会一口气删掉两个符合该特征的元素。

结合上面的分析,我们再去思考 getDerivedStateFromProps 为何会在设计层面直接被约束为一个触碰不到 this 的静态方法,其背后的原因也就更加充分了——避免开发者触碰this,就是在避免各种危险的骚操作\color{#FF3030}{避免开发者触碰 this,就是在避免各种危险的骚操作}

(3)即使你没有开启异步,React 15 下也有不少人能把自己“玩死”。

比如在 componentWillReceiveProps 和 componentWillUpdate 里滥用setState导致重复渲染死循环\color{#FF3030}{滥用 setState 导致重复渲染死循环}的,大家都懂哈(邪魅一笑)。