好家伙,
本篇讲的是数据更新请求列队处理
1.一些性能问题
数据更新的核心方法是watcher.updata方法
实际上也就是vm._updata()方法,
vm._updata()方法中的patch()方法用于将新的虚拟DOM树与旧的虚拟DOM树进行比较,
并将差异更新到实际的DOM树上.
这一步是非常消耗性能的
2."问题"实例
来写一个多次更新的例子



这里我们可以看到,updata被触发了三次,也就是 .patch()方法被触发了三次
同样的操作做了三次,显然后两次是多余的
这显然是可以优化的,我们来做些优化吧
3.优化
先讲一下思路组件与watcher一一对应
1.当三个请求同时发出,我们只进行一次操作
2.将需要操作的watcher存到一个数组中,在单次操作中调用更新方法
有点抽象
上代码:
- class Watcher{
- /*
- xxx
- */
- run(){
- this.getter()
- }
- updata() { //三次
- //注意:不要数据更新后每次都调用 get 方法 ,get 方法回重新渲染
- //缓存
- // this.get() //重新渲染
- queueWatcher(this)
- }
- }
- let queue = [] // 将需要批量更新的watcher 存放到一个列队中
- let has = {}
- let pending = false
- function queueWatcher(watcher) {
- let id = watcher.id // 每个组件都是同一个 watcher
- console.log(id) //去重
- if (has[id] == null) {//去重
- //列队处理
- queue.push(watcher)//将wacher 添加到列队中
- has[id] = true
- //防抖 :用户触发多次,只触发一个 异步,同步
- if (!pending) {
- // 异步:等待同步代码执行完毕之后,再执行
- setTimeout(()=>{
- queue.forEach(item=>item.run())
- queue = []
- has = {}
- pending = false
- },0)
- }
- pending = true
- }
- }
此处,
a. 首先获取到 watcher 的 id(假设每个组件都是同一个 watcher)。
b. 判断队列中是否已存在相同的 watcher,通过判断 has 对象中是否存在该 id 来实现。
c. 如果队列中不存在该 watcher,将其添加到队列中,并将该 id 添加到 has 对象中,表示已存在。
d. 通过 setTimeout 将队列中的所有 watcher 的 run 方法封装成一个异步任务,等待当前同步代码执行完毕后执行。
e. 设置 pending 为 true,表示当前有一个异步任务正在执行。
f. 执行setTimeout()中的代码
这样第一次执行了if()块,随后的几次操作中pending被设置为true后if()块不再执行
同步任务完成后,执行异步任务
这样,通过异步处理的方式实现了,触发多次,只执行一次的效果