Vue NextTick介绍与使用原理

目录
  • 一、NextTick是什么
    • 定义
    • 理解
    • 为什么要有nexttick
  • 二、使用场景
  • 三、实现原理

一、NextTick是什么

定义

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

理解

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

举例:

<body>
    <div id="app">
        <div>
            <button id="firstBtn" @click="testClick()" ref="aa">{{testMsg}}</button>
          </div>
    </div>
</body>
</html>
<script>
    new Vue({
        el:'#app',
        data () {
    return {
      testMsg:"原始值",
    }
  },
  methods:{
    testClick:function(){
      this.testMsg="修改后的值";
      console.log(this.$refs.aa.innerText);   //that.$refs.aa获取指定DOM,输出:原始值
      console.log(document.querySelector('#firstBtn').innerText)
    }
  }
})
</script>

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

这是因为message数据在发现变化的时候,vue并不会立刻去更新Dom,而是将修改数据的操作放在了一个异步操作队列中,如果我们一直修改相同数据,异步操作队列还会进行去重,等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新。

为什么要有nexttick

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

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

二、使用场景

this.testMsg="修改后的值";
console.log(this.$refs.aa.innerText);   //that.$refs.aa获取指定DOM,输出:原始值
Vue.nextTick(function(){
  console.log(document.querySelector('#firstBtn').innerText)
})

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

this.message = '修改后的值'
console.log(this.$refs.aa.innerText) // => '原始的值'
this.$nextTick(function () {
    console.log(this.$refs.aa.innerText) // => '修改后的值'
})

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

await Vue.nextTick()
console.log(document.querySelector('#firstBtn').innerText)

三、实现原理

  • 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);
    }
  });
  // 执行异步延迟函数 timerFunc
  if (!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 = false
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  //判断1:是否原生支持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]'
)) {
  //判断2:是否原生支持MutationObserver
  let counter = 1
  const observer = new MutationObserver(flushCallbacks)
  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  //判断3:是否原生支持setImmediate
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  //判断4:上面都不行,直接用setTimeout
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}
  • 无论是微任务还是宏任务,都会放到flushCallbacks使用
  • 这里将callbacks里面的函数复制一份,同时callbacks置空
  • 依次执行callbacks里面的函数
function flushCallbacks () {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]()
  }
}

小结:

  • 把回调函数放入callbacks等待执行;
  • 将执行函数放到微任务或者宏任务中;
  • 事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调。

到此这篇关于Vue NextTick介绍与使用原理的文章就介绍到这了,更多相关Vue NextTick内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 谈谈Vue中的nextTick

    当数据发生变化之后,DOM视图并不会立即更新,如果我们在发生变化之后立马去获取某个节点或者某个节点的值,很有可能结果就是undefined:因为Vue实现响应式并不是数据发生变化之后DOM立即变化,而是按一定的策略进行DOM的更新: 来看一个小demo: App.vue <template> <div id="app"> <div ref="message">{{msg}}</div> <div v-if=&qu

  • Vue nextTick获取更新后的DOM的实现

    目录 生命周期 update Vue.nextTick Promise 结语&参考资料 前两天在开发时遇到一个需求:打开对话框的时候自动聚焦其中的输入框.由于原生的 autofocus 属性不起作用,需要使用组件库提供的 focus 方法手动手动获取焦点.于是有如下代码: <el-button @click="openDialog">点击打开 Dialog</el-button> <el-dialog :visible.sync="dia

  • 一文学会什么是vue.nextTick()

    目录 概念 原理 举例 应该什么时候使用vue.$nextTick()呢? 概念 在下次DOM更新循环结束之后执行延迟回调,在修改数据之后立即使用这个方法,获取更新后的DOM 简单理解: 为了去解决数据更新了但是视图不更新的问题,当数据更新了,在DOM渲染后,自动执行该函数 原理 Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列.如果这个watcher被触发多次,只会被

  • Vue异步更新机制及$nextTick原理的深入讲解

    目录 前言 Vue的异步更新 DOM更新是异步的 DOM更新还是批量的 事件循环 执行过程 源码深入 异步更新队列 nextTick $nextTick 总结 一般更新DOM是同步的 既然更新DOM是个同步的过程,那为什么Vue却需要借用$nextTick来处理呢? 为什么优先使用微任务? 总结 前言 相信很多人会好奇Vue内部的更新机制,或者平时工作中遇到的一些奇怪的问题需要使用$nextTick来解决,今天我们就来聊一聊Vue中的异步更新机制以及$nextTick原理 Vue的异步更新 可能

  • 浅析vue中的nextTick

    背景 vue是异步渲染的,当data改变之后,DOM不会立刻被渲染,页面渲染时会将data的修改做整合,多次data修改只会做整合最后一次性渲染出来,这也是异步渲染的原因.只有异步渲染才可以实现整合操作. 例子 methods: { update() { for (let i = 0; i < 10; i++) { this.testNum = this.testNum + i; } }, }, 在你的 Vue 视图中, testNum 会发生变化.不过需要注意的是这个变化的过程,虽然我们把 f

  • Vue nextTick延迟回调获取更新后DOM机制详解

    目录 简述 事件循环机制 vue数据驱动视图的处理(异步变化DOM) Vue.nextTick原理 Vue.nextTick的应用 created生命周期中操作DOM 修改数据,获取DOM值 简述 相信大家在写vue项目的时候,一定会发现一个神奇的api,Vue.nextTick.为什么说它神奇呢,那是因为在你做某些操作不生效时,将操作写在Vue.nextTick内,就神奇的生效了.那这是什么原因呢? 让我们一起来研究一下. vue 实现响应式并不是数据发生变化后 DOM 立即变化,而是按照一定

  • Vue nextTick的原理解析

    使用过Vue的小伙伴们都知道,Vue里的nextTick可以获取到更新后的DOM, 今天我就来讲解下nextTick里面究竟做了什么? 开始讲解前,我们需要知道了解一个概念,那就是Event Loop Event Loop Event Loop翻译过来就是事件循环, 一个Event Loop会包括一个或多个task队列,持续线程会从队列中取出最早进入队列的任务进行执行,被取出的任务就叫做macroTask(宏任务), 每个macroTask都有一个任务源, 每个macroTask处理完之后就从队

  • Vue.nextTick纯干货使用方法详解

    目录 一.nextTick小测试 二.nextTick源码实现 1. 全局变量 2. flushCallbacks 3. nextTick的异步实现 4. nextTick方法实现 三.Vue组件的异步更新 1. queueWatcher做了什么? 2. flushSchedulerQueue做了什么? 四.回归题目本身 用过Vue的朋友多多少少都知道$nextTick- 在正式讲解nextTick之前,我想你应该清楚知道 Vue 在更新 DOM 时是异步执行的,因为接下来讲解过程会结合组件更新

  • Vue中的nextTick作用和几个简单的使用场景

    目的 理解下 nextTick 的作用和几个简单的使用场景 正文 起什么作用? 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 我想各位都知道或了解 Vue 的渲染流程,Vue 在监听到数据变化后会重新渲染,配合 VDOM 更新真实的 DOM,而 nextTick 的触发时机就是在调用方法后的第一次重新渲染完毕后. 如何使用? 有两种使用方法,一种是传入回调,另一种是 Promise,官方使用示例如下: // 修改数据 vm.msg = 'H

  • Vue NextTick介绍与使用原理

    目录 一.NextTick是什么 定义 理解 为什么要有nexttick 二.使用场景 三.实现原理 一.NextTick是什么 定义 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 理解 Vue在更新DOM时时异步执行的.当数据发生变化时,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新. 举例: <body> <div id="app"> <div> <

  • 深入学习Vue nextTick的用法及原理

    Vue.nextTick是Vue官方给我们提供的一个API(方法),作用是在下次DOM更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的DOM: 那么我们的理解是:当数据发生变化之后,DOM视图并不会立即更新,如果我们在发生变化之后立马去获取某个节点或者某个节点的值,很有可能结果就是undefined:因为Vue实现响应式并不是数据发生变化之后DOM立即变化,而是按一定的策略进行DOM的更新: 来看一个小demo: App.vue <template> <div

  • 详解Vue的异步更新实现原理

    最近面试总是会被问到这么一个问题:在使用vue的时候,将for循环中声明的变量i从1增加到100,然后将i展示到页面上,页面上的i是从1跳到100,还是会怎样?答案当然是只会显示100,并不会有跳转的过程. 怎么可以让页面上有从1到100显示的过程呢,就是用setTimeout或者Promise.then等方法去模拟. 讲道理,如果不在vue里,单独运行这段程序的话,输出一定是从1到100,但是为什么在vue中就不一样了呢? for(let i=1; i<=100; i++){ console.

  • 浅谈Vue.nextTick 的实现方法

    这是一篇继event loop和MicroTask 后的vue.nextTick API实现的源码解析. 预热,写一个sleep函数 function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms) } async function oneTick (ms) { console.log('start') await sleep(ms) console.log('end') } oneTick(3000) 解释下

  • 关于Vue.nextTick()的正确使用方法浅析

    本文主要给大家介绍了关于Vue.nextTick()的正确使用,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 什么是Vue.nextTick() 官方文档解释如下: 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 我理解的官方文档的这句话的侧重点在最后那半句获取更新后的DOM,获取更新后的DOM言外之意就是什么操作需要用到了更新后的DOM而不能使用之前的DOM或者使用更新前的DOM或出问题,所以就衍生出了这个获取更新后的D

  • Angular和Vue双向数据绑定的实现原理(重点是vue的双向绑定)

    我在整理javascript高级程序设计的笔记的时候看到面向对象设计那章,讲到对象属性分为数据属性和访问器属性,我们平时用的js对象90%以上都只是用到数据属性;我们向来讲解下数据属性和访问器属性到底是什么? 数据属性:数据属性包含一个数据值的位置,在这个位置可以读取和写入值. 访问器属性:访问器属性不包含数据值;他们包含一对getter和setter函数在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值,在写入访问器属性时,会调用setter函数并传入新值. 这里介绍的重点是

  • Vue中的scoped实现原理及穿透方法

    何为scoped? 在vue文件中的style标签上,有一个特殊的属性:scoped.当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组件元素.通过该属性,可以使得组件之间的样式不互相污染.如果一个项目中的所有style标签全部加上了scoped,相当于实现了样式的模块化. scoped的实现原理 vue中的scoped属性的效果主要通过PostCSS转译实现,如下是转译前的vue代码: <style scoped> .examp

  • 深入理解Vue nextTick 机制

    我们先来看一段Vue的执行代码: export default { data () { return { msg: 0 } }, mounted () { this.msg = 1 this.msg = 2 this.msg = 3 }, watch: { msg () { console.log(this.msg) } } } 这段脚本执行我们猜测1000m后会依次打印:1.2.3.但是实际效果中,只会输出一次:3.为什么会出现这样的情况?我们来一探究竟. queueWatcher 我们定义

随机推荐