批量异步更新策略及 nextTick 原理
2021年10月18日大约 5 分钟
为什么要异步更新
通过前面几个章节我们介绍,相信大家已经明白了 Vue.js 是如何在我们修改 data 中的数据后修改视图了。
简单回顾一下,这里面其实就是一个“setter -> Dep -> Watcher -> patch -> 视图”的过程。
假设我们有如下这么一种情况。
{{number}}
click
export default {
data () {
return {
number: 0
};
},
methods: {
handleClick () {
for(let i = 0; i true ( false ) 的形式,用来判断是否已经存在相同的 Watcher 对象 (这样比每次都去遍历 queue 效率上会高很多)。
如果目前队列 queue 中还没有这个 Watcher 对象,则该对象会被 push 进队列 queue 中去。
waiting 是一个标记位,标记是否已经向 nextTick 传递了 flushSchedulerQueue 方法,在下一个 tick 的时候执行 flushSchedulerQueue 方法来 flush 队列 queue,执行它里面的所有 Watcher 对象的 run 方法。
## flushSchedulerQueue
```js
function flushSchedulerQueue () {
let watcher, id;
for (index = 0; index < queue.length; index++) {
watcher = queue[index];
id = watcher.id;
has[id] = null;
watcher.run();
}
waiting = false;
}
举个例子
let watch1 = new Watcher();
let watch2 = new Watcher();
watch1.update();
watch1.update();
watch2.update();
我们现在 new 了两个 Watcher 对象,因为修改了 data 的数据,所以我们模拟触发了两次 watch1 的 update 以及 一次 watch2 的 update。
假设没有批量异步更新策略的话,理论上应该执行 Watcher 对象的 run,那么会打印。
watch1 update
watch1视图更新啦~
watch1 update
watch1视图更新啦~
watch2 update
watch2视图更新啦~
实际上则执行
watch1 update
watch1 update
watch2 update
watch1视图更新啦~
watch2视图更新啦~
这就是异步更新策略的效果,相同的 Watcher 对象会在这个过程中被剔除,在下一个 tick 的时候去更新视图,从而达到对我们第一个例子的优化。
我们再回过头聊一下第一个例子, number 会被不停地进行 ++ 操作,不断地触发它对应的 Dep 中的 Watcher 对象的 update 方法。
然后最终 queue 中因为对相同 id 的 Watcher 对象进行了筛选,从而 queue 中实际上只会存在一个 number 对应的 Watcher 对象。
在下一个 tick 的时候(此时 number 已经变成了 1000),触发 Watcher 对象的 run 方法来更新视图,将视图上的 number 从 0 直接变成 1000。
到这里,批量异步更新策略及 nextTick 原理已经讲完了,接下来让我们学习一下 Vuex 状态管理的工作原理。
参考资料
贡献者
binbin.hou