nextTick 使用场景和原理 ?

一、摘要

nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行nextTick 包装的方法。

nextTick 是 Vue 提供的一个异步方法,用于在下次 DOM 更新循环结束之后执行回调函数。

二、使用场景:

在 Vue 的数据变化后,想要执行一些操作,确保操作在 DOM 更新后执行,例如在数据变化后操作 DOM 元素、触发子组件的方法等。
在 Vue 的生命周期钩子函数或自定义的方法中,需要等待 DOM 更新完成后执行一些操作,如 获取更新后的dom。

三、原理:

1. JS 运⾏机制

JS 执⾏是单线程的, 它是基于事件循环的。 事件循环⼤致分为以下⼏个步骤:
(1) 所有同步任务都在主线程上执⾏, 形成⼀个执⾏栈(execution context stack) 。
(2) 主线程之外, 还存在⼀个"任务队列"(task queue) 。 只要异步任务有了运⾏结果, 就在"任务队列"之中放置⼀个事件/回调。
(3) ⼀旦"执⾏栈"中的所有同步任务执⾏完毕, 系统就会读取"任务队列", 看看⾥⾯有哪些事件。 那些对应的异步任务, 于是结束等待状态, 进⼊执⾏栈, 开始执⾏。
(4) 主线程不断重复上⾯的第三步。

2. nextTick的作用

nextTick 就是设置一个回调,用于异步执行。

this.$nextTick(() => {
    this.$refs.saveTagInput;
});

当页面上的元素被重新渲染之后,才会执行指定回调函数中的代码。 

原理:

nextTick内部就是调用宏任务和微任务来完成事件调用的机制,让nextTick里的回调在一个事件循环的最后执行。为什么要在最后呢?在最后即意味着在所有异步任务之后,记得上一点吗,“vue更新Dom是异步更新”,而我们又把nextTick里的回调放在了所有异步任务的最后,这样就解释了最开始那句话,nextTick所指定的回调会在浏览器更新DOM完毕之后再执行

在 Vue 内部,nextTick 方法使用了 microtask(微任务)或者 microtask + macrotask(宏任务)的方式实现异步操作。具体使用哪种方式取决于当前环境的支持情况。
当调用 nextTick 方法时,Vue 会将回调函数推入一个异步队列中,等待下次的事件循环(Event Loop)开始时执行。
在 microtask 模式下,nextTick 的回调函数会在当前微任务队列执行完毕后立即执行,比如 Promise 的 then 方法。
在 microtask + macrotask 模式下,nextTick 的回调函数会在当前微任务队列执行完毕后,进入宏任务队列,等待下一次事件循环时执行,比如 setTimeout 的回调函数。
nextTick 的使用场景主要是在需要等待 Vue 的 DOM 更新完成后执行一些操作,以确保操作在正确的时机进行。例如,当需要操作已经更新的 DOM 元素或者需要在 Vue 的生命周期钩子函数之后执行一些逻辑时,可以使用 nextTick 来确保操作在正确的时机进行,避免出现错误或不一致的情况。

3.Vue在一个tick中多次更新数据页面只会更新一次

即使在 Vue 中多么频繁地修改数据,最后 Vue 页面只会更新一次。

例如:
数据 name 被 页面引用,name 会收集到 页面的 watcher;
name 被修改时,会通知所有收集到的 watcher 进行更新(watcher.update);
如果name 一时间被修改三次时,按道理应该会通知三次 watcher 更新,那么页面会更新三次,但是最后只会更新一次。
这是因为:
当数据变化后,把 watcher.update 函数存放进 nextTick 的 回调数组中,并且会做过滤。
通过 watcher.id 来判断 回调数组 中是否已经存在这个 watcher 的更新函数不存在,才 push。
之后 nextTick时 遍历回调数组,便会执行了更新。

所以当三次修改数据的时候,会 push 回调数组 三个 watcher.update,但是只有第一次是 push 成功的,其他的会被过滤掉,因为已经存在了。
所以,不管你修改多少次数据,nextTick 的回调数组中只存在唯一一个 watcher.update,从而页面只会更新一次。
 

猜你喜欢

转载自blog.csdn.net/muzidigbig/article/details/131602344