异步队列渲染

上一篇文章是在vue2.0 中通过Object.defineProperty去拦截并监听数据变化的响应式原理,这篇文章将会沿着图谱继续深入探索,在依赖被通知变化了之后,会触发vue当中的异步渲染队列,这里我们就是要研究以下几点:

  1. 为什么要设计成异步渲染队列
  2. 渲染是如何实现的
  3. 因为异步渲染队列而产生的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中会有两种场景:

  1. Vue.nextTick([callback,context])
  2. vm.$nextTick([callback])
  • 将回调延迟到下次DOM更新循环之后执行。
  • 通常用于在修改数据之后使用这个方法,在回调中获取更新后的DOM
  • 实例中的方法会将callback的this 会自动绑定到实例上
  • 在生命周期钩子函数中mounted和updated直接执行的代码并不能保证子组件有完全的挂载或者更新,这个时候我们可以使用this.$nextTick(function(){})在整个视图都渲染完成后进行一些操作,这个过程是可靠的。

总结

这篇文章主要是对Vue异步渲染队列的研究,我们可以看出主要是对于模板性能的优化,所以产生了异步渲染队列的概念,同样产生了Vue.nextTick 的api,我们可以通过api去处理在模板更心之后,或者子组件更i性能后的逻辑。
 

免责声明

本文只是在学习Vue 异步渲染中的一些笔记,文中的资料也会涉及到引用,具体出处不详,商业用途请谨慎转载。

vue为什么要设计成异步队列渲染的更多相关文章

  1. React中this.setState是同步还是异步?为什么要设计成异步?

    在使用react的时候,this.setState为什么是异步呢? 一直以来没有深思这个问题.昨天就此问题搜索了一下. react创始人之一 Dan Abramovgaearon在GitHub上回答了 ...

  2. 基于异步队列的生产者消费者C#并发设计

    继上文<<基于阻塞队列的生产者消费者C#并发设计>>的并发队列版本的并发设计,原文code是基于<<.Net中的并行编程-4.实现高性能异步队列>>修改 ...

  3. 【转】从Vue.js源码看异步更新DOM策略及nextTick

    在使用vue.js的时候,有时候因为一些特定的业务场景,不得不去操作DOM,比如这样: <template> <div> <div ref="test" ...

  4. Vue源码探究-虚拟DOM的渲染

    Vue源码探究-虚拟DOM的渲染 在虚拟节点的实现一篇中,除了知道了 VNode 类的实现之外,还简要地整理了一下DOM渲染的路径.在这一篇中,主要来分析一下两条路径的具体实现代码. 按照创建 Vue ...

  5. vue.js数据可以在页面上渲染成功却总是警告提示某个字段“undefined”未定义

    最近在开发公司的一个后端管理系统,用的是比较流行的vue框架.在开发过程中,总是出现各种各样的报错问题,有警告的,有接口不通的,有自己马虎造成的低级错误的等等,这些错误在一些老司机面前分分钟解决,但今 ...

  6. .Net中的并行编程-4.实现高性能异步队列

    上文<.Net中的并行编程-3.ConcurrentQueue实现与分析>分析了ConcurrentQueue的实现,本章就基于ConcurrentQueue实现一个高性能的异步队列,该队 ...

  7. [js高手之路]javascript腾讯面试题学习封装一个简易的异步队列

    这道js的面试题,是这样的,页面上有一个按钮,一个ul,点击按钮的时候,每隔1秒钟向ul的后面追加一个li, 一共追加10个,li的内容从0开始技术( 0, 1, 2, ....9 ),首先我们用闭包 ...

  8. vue和jQuery嵌套实现异步ajax通信

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  9. 如何设计一个异步Web服务——接口部分

    需求比较简单,提供一个异步Web服务供使用者调用.比如说,某应用程序需要批量地给图片加lomo效果.由于加lomo效果这个操作非常消耗CPU资源,所以我们需要把这个加lomo效果的程序逻辑放到一台单独 ...

随机推荐

  1. 【STM32】WS2812介绍、使用SPI+DMA发送数据

    这篇要使用到SPI+DMA,需要了解的话,可以参考我另两篇博客 时钟:https://www.cnblogs.com/PureHeart/p/11330967.html SPI+DMA通信:https ...

  2. Oracle存储过程游标for循环怎么写

    一.不带参数的游标for循环 首先编写存储过程的整体结构,如下: create or replace procedure test_proc is v_date date; --变量定义 begin ...

  3. 端口占用,windows下通过命令行查看和关闭端口占用的进程

    1.查找所有端口号对应的PID 端口号:8080 命令:netstat -ano|findstr "8080" 2.找到端口的PID并关闭 PID:1016 命令:taskkill ...

  4. JSP常见的状态码

    1.404错误 -- 找不到访问的页面或资源 a.URL输入错误: b.未部署项目. 2.500错误 -- JSP页面代码有错误 3.302状态码+200状态码 -- 重定向 4.200状态码 -- ...

  5. 【Keras】神经网络的搭建

    Dense层的使用方法 参考:https://blog.csdn.net/qq_34840129/article/details/86319446 keras.layers.core.Dense( u ...

  6. 从一次解决Nancy参数绑定“bug”开始发布自己的第一个nuget包(上篇)

    起因 最近,同事跟我说,他们负责的一个Api程序出现了一些很奇怪的事情.这个Api是为环保局做的一个扬尘质控大屏提供数据的,底层是基于Nancy做的.因为发现有些接口的数据出现异常,他就去调试了一下, ...

  7. Nginx模块之stub_status

    目录 一.介绍 二.使用 三.参数 一.介绍 Nginx中的stub_status模块主要用于查看Nginx的一些状态信息. 当前默认在nginx的源码文件中,不需要单独下载 二.使用 本模块默认是不 ...

  8. tableau添加参考线

    一.将数据窗口切换至分析窗口-点击自定义-参考线 二.出现编辑参考线和参考区间的界面(整个表指的是整个视图,每区指的是如下2018就是一个区,每单元格指的是横轴的最小值) 三.我们分别为每区添加最大值 ...

  9. 【已解决】关于echarts的splitArea分割区域背景闪烁问题

    (x轴)使用时间类型(type: "time"),并且x轴使用splitArea划分后使用color属性设定分割区域颜色.        同时使用dataZoom设置区域缩放,在局 ...

  10. 熔断和降级的初步详解实现(NET Core控制台输出讲解Polly)

    概述 很多朋友包括我,对于"八股文"可以说是比较熟练的,每次面试前都会专研不少东西,各种固定答案.专业术语都是张口就来,一个字,稳. 八股文:程序员八股文是指程序员在面试过程中经常 ...