主题
实现同步调度流程
更新到底是同步还是异步?
class App extends React.Component {
onClick() {
this.setState({a: 1});
console.log(this.state.a);
}// ...省略其他代码
}当前的现状: 从触发更新到render ,再到commit 都是同步的 多次触发更新会重复多次更新流程 可以改进的地方:「多次触发更新,只进行一次更新流程」 Batched Updates (批处理):多次触发更新,只进行一次更新流程 将多次更新合并为一次,理念上有点类似防抖、节流,我们需要考虑合并的时机是: 宏任务? 微任务? 用三款框架实现Batched Updates ,打印结果不同: React Vue3 Svelte 结论:React 批处理的时机既有宏任务,也有微任务。 本节课我们来实现「微任务的批处理」。 新增调度阶段 既然我们需要「多次触发更新,只进行一次更新流程」,意味着我们要将更新合并,所以在:
render 阶段
commit 阶段的基础上增加schedule 阶段(调度阶段)
对update的调整
「多次触发更新,只进行一次更新流程」中「多次触发更新」意味着对于同一个fiber ,会 创建多个update :
js
const onClick = () => {
// 创建3个update
updateCount((count) => count + 1);
updateCount((count) => count + 1);
updateCount((count) => count + 1);
};「多次触发更新,只进行一次更新流程」,意味着要达成3个目标:
- 需要实现一套优先级机制,每个更新都拥有优先级
- 需要能够合并一个宏任务/微任务中触发的所有更新
- 需要一套算法,用于决定哪个优先级优先进入render阶段
实现目标1:Lane模型
包括: lane (二进制位,代表优先级) lanes (二进制位,代表lane 的集合) 其中: lane 作为update 的优先级 lanes 作为lane 的集合
lane的产生
对于不同情况触发的更新,产生lane 。为后续不同事件产生不同优先级更新做准备。 如何知道哪些lane 被消费,还剩哪些lane 没被消费?
对FiberRootNode的改造
需要增加如下字段: 代表所有未被消费的lane 的集合 代表本次更新消费的lane
实现目标2、3
需要完成两件事: 实现「某些判断机制」,选出一个lane 实现类似防抖、节流的效果,合并宏/微任务中触发的更新
render阶段的改造
processUpdateQueue 方法消费update 时需要考虑: lane 的因素 update 现在是一条链表,需要遍历
commit阶段的改造
移除「本次更新被消费的lane」。