Skip to content

实现同步调度流程

更新到底是同步还是异步?

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个目标:

  1. 需要实现一套优先级机制,每个更新都拥有优先级
  2. 需要能够合并一个宏任务/微任务中触发的所有更新
  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」。

用心学习,用代码说话 💻