简单的代码开始:

var app = new Vue({el: '#app',data: {message: 'Hello Vue!'},watch: {message (val) {console.log('mutation')}},mounted () {this.message = 1this.message = 2this.message = 3}
})

首先看这个例子中,连续3次触发了mutation,那么watch中的cb会被执行几次呢?

答案是一次。

那么为什么会是一次呢?本文会围绕着这个问题的解释来粗浅地讨论一下Vue中批量更新的原理。

首先要知道,msg这个key,是通过Object.defineProperty被监听了的,Vue通过这个api实现在key被set的时候(也就是this.msg = xxx这种操作),触发所有订阅了这个key的Watcher的update方法。

这里引入了一个Watcher的概念,那么这个Watcher是什么呢?

从语义上理解,Wathcer其实类似于一个key的观察者,当key被set的时候,Watcher会调用自身的update方法。

在 mountComponent 也就是加载组件的时候会调用 Watcher 创建观察者。

new Watcher(vm, updateComponent, noop, {before () {if (vm._isMounted && !vm._isDestroyed) {callHook(vm, 'beforeUpdate')}}
}, true /* isRenderWatcher */)

监听到一个set引起的mutation就立即同步执行一次cb吗?

显然是不可以的。

举个例子:

for (let i = 0; i < 1000; i++) {this.msg = `循环了${i}次`;
}

假如对于这种操作,1000次里面每次Watcher都要响应执行一次update,那可能是有很大的性能开销的。像本文的这个例子中update其实就是一个console.log,但是如果cb是一个开销比较大的方法,那么就可能会引起性能问题了。

所以update操作一定是异步的。

虽然知道要通过异步来解决,但具体是如何解决的呢?Vue的做法是把调用cb放到了一个micro task或者macro task队列中,具体放到微任务队列还是宏任务队列要看当前的运行环境是否支持Promise、MutationObserver、setImmediate这几个相当于放入微任务队列的api,支持就会放在微任务队列,不支持则使用setTimeout这个api把调用cb放到宏任务队列里。

不管放到微任务队列还是宏任务队列,调用cb都会在所有的同步代码执行完毕后执行。这一点涉及到event loop的知识,因为总是先执行所有的同步代码,然后从微任务队列中按顺序执行,微任务队列空了才会从宏任务队列中取出一条执行。如果此时微任务队列还有任务,那么就会继续按照这个循环执行,这个就是event loop。

通俗地理解Vue的行为就是在监听到key的mutation之后key的Watcher都会触发update,想要调用自身的cb属性,但是Vue仅仅是答应会在未来的某个时刻执行Watcher的这个update请求也就是调用它的cb,并且在调用之前都不会再受理该Watcher的update的请求。

下面看看源码

function queueWatcher (watcher) {const id = watcher.idif (has[id] == null) {has[id] = trueif (!flushing) {queue.push(watcher)} else {let i = queue.length - 1while (i > index && queue[i].id > watcher.id) {i--}queue.splice(i + 1, 0, watcher)}if (!waiting) {waiting = trueif (process.env.NODE_ENV !== 'production' && !config.async) {flushSchedulerQueue()return}nextTick(flushSchedulerQueue)}}
}

重点是 nextTick 源码

let timerFuncif (typeof Promise !== 'undefined' && isNative(Promise)) {const p = Promise.resolve()timerFunc = () => {p.then(flushCallbacks)if (isIOS) setTimeout(noop)}isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (isNative(MutationObserver) ||MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {let counter = 1const observer = new MutationObserver(flushCallbacks)const textNode = document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})timerFunc = () => {counter = (counter + 1) % 2textNode.data = String(counter)}isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {timerFunc = () => {setImmediate(flushCallbacks)}
} else {timerFunc = () => {setTimeout(flushCallbacks, 0)}
}function nextTick (cb, ctx) {let _resolvecallbacks.push(() => {if (cb) {try {cb.call(ctx)} catch (e) {handleError(e, ctx, 'nextTick')}} else if (_resolve) {_resolve(ctx)}})if (!pending) {pending = truetimerFunc()}if (!cb && typeof Promise !== 'undefined') {return new Promise(resolve => {_resolve = resolve})}
}

Vue的批量更新原理相关推荐

  1. vue created 调用方法_深入解析 Vue 的热更新原理,偷学尤大的秘籍?

    大家都用过 Vue-CLI 创建 vue 应用,在开发的时候我们修改了 vue 文件,保存了文件,浏览器上就自动更新出我们写的组件内容,非常的顺滑流畅,大大提高了开发效率.想知道这背后是怎么实现的吗, ...

  2. 深入解析 Vue 的热更新原理,尤大是如何巧用源码中的细节?

    大家都用过 Vue-CLI 创建 vue 应用,在开发的时候我们修改了 vue 文件,保存了文件,浏览器上就自动更新出我们写的组件内容,非常的顺滑流畅,大大提高了开发效率.想知道这背后是怎么实现的吗, ...

  3. Vue响应式更新原理(个人总结)

    1.响应式原理 把js对象传入一个vue实例作为data项,进行遍历,使用Object.defineProperty把这些属性转为getter/setter. Object.definePropert ...

  4. mysql批量更新方法

    目录 方法一 replace into 批量更新 方法二 insert into 批量更新 方法三 临时表 批量更新 方法四 case when 批量更新 本篇文章实验mysql版本为5.7.20  ...

  5. VUE双向绑定的原理(简单版)+虚拟DOM 节点的创建和更新

    手动敲敲代码,就很容易理解了,供参考 1.以下是VUE双向绑定的原理(简单版) 主要是监听和defineProperty实现简单的双向绑定 <html><head></h ...

  6. vue虚拟don diff原理

    一.前言 Vue的核心是双向绑定和虚拟DOM(下文我们简称为vdom),关于双向绑定可以参阅木琴的文章<剖析Vue原理&实现双向绑定MVVM>,vdom是树状结构,其节点为vnod ...

  7. java批量事物管理_[疯狂Java]JDBC:事务管理、中间点、批量更新

    1. 数据库事务的概念: 1) 事务的目的就是为了保证数据库中数据的完整性: 2) 设想一个银行转账的过程,如果分两步,第一步是A的账户-1000,第二步是B的账户+1000,这两个动作必须是连贯的, ...

  8. vue指令写在html中的原理,详解Vue中的MVVM原理和实现方法

    对Vue中的MVVM原理解析和实现首先你对Vue需要有一定的了解,知道MVVM.这样才能更有助于你顺利的完成下面原理的阅读学习和编写下面由我阿巴阿巴的详细走一遍Vue中MVVM原理的实现,这篇文章大家 ...

  9. PHP如何批量更新MYSQL中的数据

    最近项目需要用到批量更新数据库里的数据,在网上找了一下这方面的例子,觉得这个还不错,分享给大家. 在这个业务里里面涉及到了更新两张数据表,那么大家是不是会想到非常简单,马上上代码 $sql = &qu ...

最新文章

  1. 十步图解CSS的position
  2. 问题解决-Failed to resolve: com.android.support.constraint:constraint-layout:1.0.0-alpha7
  3. php 图片透明,PHP怎么把一张图片透明化
  4. HTML5 file api读取文件的MD5码工具
  5. Redhat与ubuntu配置网卡
  6. 如何将数据渲染到页面上?
  7. 「Photoshop 入门教程」了解 Photoshop 工作区
  8. 孪生再世代表数字几_征稿通知 |高电压技术“数字孪生技术在能源互联网中的应用”专题征稿通知...
  9. 分享一个自动刷抖音的代码 auto js
  10. r语言 断轴 画图_R语言之画图(一)
  11. 影片剪辑app android,4款经典的手机影片剪辑App
  12. 120_x轴与y轴平移【transform: translateX(n) translateY(n)】利用定位和变形使元素水平垂直居中
  13. 信用卡诈骗检测(经过测试)
  14. sqlite查询空日期类型_sqlite数据类型(时间 日期 ) timestamp 使用
  15. 华为物联网操作系统 LiteOS
  16. 五阶魔方公式java_五阶魔方降阶法公式是什么?
  17. 已知函数fx=sin(wx+φ)_已知函数fx=Asin(wx+φ) (x∈R,A0,w0,0
  18. IMX6ULL - 移植uboot-imx_v2020.04_5.4.70_2.3.0
  19. plot画图 python 双线_Python使用多种滤波器对脑电数据去除伪影
  20. 10000多个QQ空间透明flash素材大观园

热门文章

  1. 喜欢 TypeScript 的人,一点都不比 Python 少
  2. 最受欢迎 Top 12 Python 开源框架,你都用过吗?| 原力计划
  3. 阿里开源 GNN 框架 Graph-Learn,实现了各类可复用模型和编程接口!
  4. 【正在直播】:CSDN直播间专属福利!1399买Airpods Pro
  5. 十分钟上手 React+MirrorX,从此前端大神代码不再难懂 | 原力计划
  6. 谁将称霸跨平台应用市场?
  7. 黑莓手机将停售;三大运营商:疫情防控期间用户欠费不停机;Chrome 测试移除搜索结果页网址 | 极客头条...
  8. 微服务架构的 10个 最佳实践 !
  9. 中国移动:部分 5G 手机可能有网连不上;iOS 13 出现严重漏洞;ReactOS 0.4.12发布 | 极客头条​...
  10. 程序员该如在低代码和无代码开发中抉择?