vue为什么要设计成异步队列渲染
异步队列渲染
上一篇文章是在vue2.0 中通过Object.defineProperty去拦截并监听数据变化的响应式原理,这篇文章将会沿着图谱继续深入探索,在依赖被通知变化了之后,会触发vue当中的异步渲染队列,这里我们就是要研究以下几点:
- 为什么要设计成异步渲染队列
- 渲染是如何实现的
- 因为异步渲染队列而产生的nextTick, 并了解nextTick的使用场景
对上次的代码做一个改造,使得模板依赖的变量增加时,如下面这样
let x = ref(1); let y = ref(1); let z = ref(1); onXChanged(() => { console.log(`x: ${x.value}, y: ${y.value}, z: ${z.value}`); }); x.value = 2; y.value = 3; z.value = 4;
控制台打印的结果如下:
我们可以看出x, y, z 的更改分别被执行了1次,那这些数据都是存在于模板中的,所以我们会认为这个模板被渲染了3次。那实际项目中, 多次渲染就产生很多的开销了。 所以从上面的这个例子我们发现,当模板中存在多出变量依赖的时候,每一个变量修改的时候,都会导致一次渲染,是否可以优化?
我们可以思考下实际工作中遇到的场景:
平时我们工作的时候,如果每隔一段时间,也许是5min或者10min,都会有一个策划向你提出需求时,或者一个新员工向你请教问题,或者一个测试人员向你提出bug, 如果这种频率出现很高,那我相信它一定会占用你的正常编码时间,使得你更加不能专注的完成你的本职工作了,那么我们一般可能都会选择把他们要做的事情先放到一边,让他们等一等,和自己约定一个时间,也许是45分钟或者1个小时,那么可以让自己在这段时间更加专注自己的本职工作,然后再去处理其他的事情。
其实vue中异步更新队列, 逻辑也是差不多的。当我们在一个函数块中包含对多个变量的依赖时,可以将这些依赖放入一个队列中,等到当前函数更新一次完成后,在进行批量的渲染操作,下面是具体的实现代码
(function () { // let f = n => n * 100 + 200; let active; let watch = function (cb) { active = cb; active(); active = null; } // 需要有个队列来存储各项任务 let queue = []; // 通过微任务方式去执行队列中的任务 let nextTick = cb => Promise.resolve().then(cb); // 将任务添加到队列 let queueJob = job => { if (!queue.includes(job)) { queue.push(job) nextTick(flushJobs) } } // 执行队列中的任务 let flushJobs = () => { let job; while ((job = queue.shift()) !== undefined) { job() } } // 收集更多依赖 class Dep { // 依赖收集,将响应依赖添加到deps中 constructor() { this.deps = new Set(); } depend() { if (active) { this.deps.add(active) } } // 通知依赖更新 notify() { // 将任务加到队列中 this.deps.forEach(dep => queueJob(dep)) } } let ref = initValue => { let value = initValue; let dep = new Dep(); return Object.defineProperty({}, "value", { get() { dep.depend(); return value; }, set(newValue) { value = newValue; dep.notify() } }) } let x = ref(1); let y = ref(1); let z = ref(1); watch(() => { console.log(`x: ${x.value}, y: ${y.value}, z: ${z.value}`); }); x.value = 2; y.value = 3; z.value = 4; })()
测试结果如下:
这样我们可以让所以依赖更新完后,模板重新渲染一次
上面的 nextTick 返回一个Promise,需要注意的是在下次Dom更新循环结束之后执行延迟回调。
在 Vue中会有两种场景:
- Vue.nextTick([callback,context])
- vm.$nextTick([callback])
- 将回调延迟到下次DOM更新循环之后执行。
- 通常用于在修改数据之后使用这个方法,在回调中获取更新后的DOM
- 实例中的方法会将callback的this 会自动绑定到实例上
- 在生命周期钩子函数中mounted和updated直接执行的代码并不能保证子组件有完全的挂载或者更新,这个时候我们可以使用this.$nextTick(function(){})在整个视图都渲染完成后进行一些操作,这个过程是可靠的。
总结
这篇文章主要是对Vue异步渲染队列的研究,我们可以看出主要是对于模板性能的优化,所以产生了异步渲染队列的概念,同样产生了Vue.nextTick 的api,我们可以通过api去处理在模板更心之后,或者子组件更i性能后的逻辑。免责声明
本文只是在学习Vue 异步渲染中的一些笔记,文中的资料也会涉及到引用,具体出处不详,商业用途请谨慎转载。
- 为什么vue采用异步渲染
- 基于异步队列的生产者消费者C#并发设计
- vue 异步更新队列 $nextTick
- Vue异步更新队列
- 从壹开始前后端分离 [ vue + .netcore 补充教程 ] 二九║ Nuxt实战:异步实现数据双端渲染
- 理解vue的重要机制:异步更新队列
- Vue异步更新队列及nextTick
- 记一次vue 普通异步请求微信二进制二维码 乱码 问题解决然后渲染
- vue用api获取直接赋值的数组为什么没有渲染在前端
- C#实现异步消息队列
- iOS中的GCD(1)---串、并行队列和同、异步添加
- Vue 列表渲染性能优化原理
- 为什么要学习设计模式(Design Patterns) - 软件设计大师之路
- 华硕首款5G手机渲染图曝光:独特滑盖设计
- 基于事件的异步设计模式
- swoole 异步队列简明教程
- 转载 --Android 异步链式调用设计
- Vue模板语法 mustache语法列表渲染 事件
- Vue-ssr服务器端渲染 webpack4+koa2配置服务器端渲染 开发环境与生产环境配置(一)
- Vue服务端渲染(Nodejs)