Vue 中为什么要有nextTick

本文分享自华为云社区《Vue 中的 nextTick 有什么作用?》,作者:CoderBin。

一、什么是nextTick

先看看官方对其的定义:

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

什么意思呢?

我们可以理解成,Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新

举个例子:

Html结构

{{ message }}

构建一个vue实例

const vm = new Vue({el: ‘#app’,data: {message: ‘原始值’}})

修改message

this.message = ‘修改后的值1’ this.message = ‘修改后的值2’ this.message = ‘修改后的值3’

这时候想获取页面最新的DOM节点,却发现获取到的是旧值

console.log(vm.$el.textContent) // 原始值

这是因为message数据在发现变化的时候,vue并不会立刻去更新Dom,而是将修改数据的操作放在了一个异步操作队列中

如果我们一直修改相同数据,异步操作队列还会进行去重

等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新

为什么要有nexttick

举个例子

{{num}} for(let i=0; i<100000; i++){ num = i }

如果没有 nextTick 更新机制,那么 num 每次更新值都会触发视图更新(上面这段代码也就是会更新10万次视图),有了nextTick机制,只需要更新一次,所以nextTick本质是一种优化策略

二、使用场景

如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()

  • 第一个参数为:回调函数(可以获取最近的DOM结构)
  • 第二个参数为:执行函数上下文

// 修改数据vm.message = ‘修改后的值’// DOM 还没有更新console.log(vm.$el.textContent) // 原始的值Vue.nextTick(function () {// DOM 更新了console.log(vm.$el.textContent) // 修改后的值})

组件内使用 vm.$nextTick() 实例方法只需要通过this.$nextTick(),并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

this.message = ‘修改后的值’console.log(this.$el.textContent) // => ‘原始的值’this.$nextTick(function () {console.log(this.$el.textContent) // => ‘修改后的值’})

$nextTick() 会返回一个 Promise 对象,可以是用async/await完成相同作用的事情

this.message = ‘修改后的值’console.log(this.$el.textContent) // => ‘原始的值’await this.$nextTick()console.log(this.$el.textContent) // => ‘修改后的值’

三、实现原理

源码位置:/src/core/util/next-tick.js

callbacks也就是异步操作队列

callbacks新增回调函数后又执行了timerFunc函数,pending是用来标识同一个时间只能执行一次

export function nextTick(cb?: Function, ctx?: Object) {let _resolve;// cb 回调函数会经统一处理压入 callbacks 数组callbacks.push(() => {if (cb) {// 给 cb 回调函数执行加上了 try-catch 错误处理try {cb.call(ctx);} catch (e) {handleError(e, ctx, ‘nextTick’);}} else if (_resolve) {_resolve(ctx);}});// 执行异步延迟函数 timerFuncif (!pending) {pending = true;timerFunc();}// 当 nextTick 没有传入函数参数的时候,返回一个 Promise 化的调用if (!cb && typeof Promise !== ‘undefined’) {return new Promise(resolve => {_resolve = resolve;});}}

timerFunc函数定义,这里是根据当前环境支持什么方法则确定调用哪个,分别有:

Promise.then、MutationObserver、setImmediate、setTimeout

通过上面任意一种方法,进行降级操作

export let isUsingMicroTask = falseif (typeof Promise !== ‘undefined’ && isNative(Promise)) {//判断1:是否原生支持Promiseconst 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]’)) {//判断2:是否原生支持MutationObserverlet 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)) {//判断3:是否原生支持setImmediatetimerFunc = () => {setImmediate(flushCallbacks)}} else {//判断4:上面都不行,直接用setTimeouttimerFunc = () => {setTimeout(flushCallbacks, 0)}}

无论是微任务还是宏任务,都会放到flushCallbacks使用

这里将callbacks里面的函数复制一份,同时callbacks置空

依次执行callbacks里面的函数

function flushCallbacks () {pending = falseconst copies = callbacks.slice(0)callbacks.length = 0for (let i = 0; i < copies.length; i++) {copies[i]()}}

四、最后总结

  • 把回调函数放入callbacks等待执行
  • 将执行函数放到微任务或者宏任务中
  • 事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调
  • 声明:本文内容整理自网络,观点仅代表原作者本人,投稿号仅提供信息发布服务。如有侵权,请联系管理员。

    (0)
    上一篇 2022年10月17日 21:16
    下一篇 2022年10月17日 21:16

    热点推荐

    • 国外进口化妆品进货源在哪里

      有关国内的化妆品市场还是非常火爆的,每年加入到这个行业的商家无数,而大家对国外进口的化妆品货源更为关注。那么,国外进口化妆品进货源在哪里?现在进口化妆品批发在哪里拿货最便宜呢?今天小编也将给大家分享一份靠谱的国外进口化妆品进货源渠…

      热点 2023年8月17日
      181
    • 摔手机、嘲讽粉丝买不起蛋黄酥 东方甄选主播天权道歉

      快科技12月16日消息,东方甄选官方账号发布主播天权的道歉视频。视频中,天权对自己昨晚在直播间的过激言论和不合时宜的举动”给关注者带来不好的购物体验,向网民道歉。 他表示自己情绪失控,非常后悔自己昨天的行为,会进行深刻的检讨,并说…

      热点 2023年12月17日
      93
    • 我还是很喜欢你,像风走了八万里,不问归期

      假如这一生我有99次好运,我愿意把96次都分给你,只留三次给自己。一次是遇见你,一次是我爱的你也恰好爱上我,一次是永远陪你走下去。 多么动人的情话,可偏偏在这个隔着屏幕交流的新时代,爱意的表达似乎变得很容易。一键粘贴复制,爱的情话…

      热点 2023年5月6日
      110
    • 孙小果死刑复核裁定书曝光(孙小果案刑事裁定书)

      本期案例为黄某猛走私、贩卖、运输、制造毒品案,对于综合运用《刑事诉讼法》的相关知识处理案件具有较强的参考意义。下面我们具体来看: 难度:偏难 答题模式:问答模式 考点:技术侦查、非法证据、鉴定人出庭、死刑复核程序以及死刑的执行等 …

      热点 2022年10月13日
      175
    • “电视一哥”康辉:曾创下22分38秒超长口播记录,因失误不断悔改

      说起康辉的名字我们大家肯定都不陌生了,这么长时间以来康辉都在给我们大家带来优秀的节目,并且能够进入电视的主持人都是有着非常厉害的主持能力的,康辉更是直接被我们大家称为是电视门面。 电视门面康辉也是创下过22分38秒的超长口播时间 …

      2022年12月9日 热点
      171
    • 微博会员多少钱一个(微博会员多少钱)

      今天小编给各位分享微博会员多少钱的知识,其中也会对微博会员多少钱一个进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧! 微博会员多少钱 1、微博会员季卡卡30元钱。京东微博旗舰店微博会员季卡现价30元,9日-1…

      热点 2023年6月10日
      245
    • 第一款24GB内存手机开启预售:7499元

      红魔8S Pro系列已经在京东自营店上架并开始预售,起售价为3999元(8GB 128GB),而顶配版24GB 1TB的售价则为7499元。然而,需要注意的是,24GB内存版本并未参与此次预售。 这款手机可以说是目前最强悍的性能旗…

      热点 2023年7月6日
      93
    • 财政部公布:发行7500亿元特别国债

      中新社北京12月9日电 (记者 赵建华)为筹集财政资金,支持国民经济和社会事业发展,中国财政部决定发行2022年特别国债。 财政部9日公布的信息显示,本期国债为3年期固定利率附息债,发行面值7500亿元(人民币,下同),可以上市交…

      热点 2022年12月11日
      105
    • 斗鱼CEO“涉赌”后,又被曝出更大猛料,大主播们开始慌了

      在阅读此文之前,辛苦点击右上角的“关注”,既方便您进行讨论与分享,又能给您带来不一样的参与感,感谢您的支持! 近日,一场震惊整个游戏直播界的风波在斗鱼平台上掀起了巨大的波澜。这场风波的中心人物,正是斗鱼的首席执行官陈少杰。他因涉嫌…

      热点 2023年11月29日
      93
    • 电源线的型号规格有哪些,电缆线规格型号及参数

      电源线代表型号RVV也称软电线、双绞线,芯线由有限根数小截面的导体组成的软电线,其芯线根数不定,两根或以上,外面有PVC护套,使用时要求柔软,并在结构和材料上能满足柔软性要求的电线。 电源线主要用于750V以下仪表仪器、照明、电器…

      热点 2022年10月17日
      178

    发表回复

    您的邮箱地址不会被公开。 必填项已用 * 标注