Home > Web Front-end > Vue.js > Let me give you a deeper understanding of this.$nextTick!

Let me give you a deeper understanding of this.$nextTick!

青灯夜游
Release: 2022-12-21 20:43:10
forward
2001 people have browsed it

Let me give you a deeper understanding of this.$nextTick!

It’s almost 2023, don’t you still know how to do this.$nextTick? Vue2 has been out for almost 10 years, and Vue3 has been out for more than two years. That’s right! It's embarrassing to say it. I only know this.nextTick now (to tell the truth). Okay, let's search it on Baidu first, click, click, click... I jumped to the Vue.js official website document very quickly, and suddenly I found a sentence in the document? :

nextTick: Execute the delayed callback after the end of the next DOM update cycle. Use this method immediately after modifying the data to get the updated DOM. It has two parameters: the first parameter is Callback function, which provides promise call if not passed; the second parameter is Execution environment context, if not passed, it will be automatically bound to on the instance on which it is called. [Related recommendations: vuejs video tutorial, web front-end development]

Let’s first take a look at what nextTick is?

console.log(this.$nextTick);
// 控制台打印
if(fn){
  return nextTick(fn, this);
}
Copy after login

We can see that nextTick is a method. The method has two parameters: fn and this. fn is the callback function that needs to be passed. this is what is said execution environment context. So the question is, How to implement delayed callback in Vue until the next DOM update is completed? Let’s take a look at the following example first:

<div ref="test1">created:{{message}}</div>
// vue实例
data: {
    message: "Hello World!",
},
created(){
    this.message = &#39;你好,世界!&#39;;
    console.log(this.$refs.test1.innerText);// 报错
    // TypeError: Cannot read properties of undefined (reading &#39;innerText&#39;)
    this.$nextTick(()=>{
         console.log(&#39;test1 nextTick:&#39;,this.$refs.test1.innerText);// 你好,世界!
    });
},
Copy after login

From the above example, the DOM is manipulated in the created life cycle, but we all know that the created life cycle only initializes the data, and there is no rendering during this period. DOM, if we directly operate the DOM, we cannot find the DOM element. Then the question arises: Why can we get the DOM element by placing it in nextTick? Isn’t this obvious? Wait until the DOM is rendered and then call it to get it. Then you know that nextTick is used to wait until the next time the DOM is rendered before calling the DOM operation code in nextTick . So the question comes again, what exactly does nextTick do? Let's analyze the nextTick principle of Vue2 and Vue3 versions from the source code level.

Vue2 version of nextTick

Since Vue exposes the nextTick method to developers, three main things are done in this method, Callback function Add , to delay the execution of the callback function , to determine whether the current nextTick is passed into the callback function . If not passed, it is a Promise, this.$nextTick.then(()=>{}), and is processed as Promise.

Let me give you a deeper understanding of this.$nextTick!

  • The callback function is added to the callbacks array, because there may be multiple nextTick functions in the current scope.

Let me give you a deeper understanding of this.$nextTick!

  • Determine whether the current nextTick has been marked as pending=true, that is, it is being executed. If not, execute timerFunc (Asynchronous execution function is used Call flushCallbacks function asynchronously). The execution of timerFunc determines whether the current environment supports promise, MutationObserver, setImmediate, and setTimeout. The priority is from front to back, divided into four situations:
  • Use Promise first, if the current The environment supports promises. NextTick uses promises by default to execute delayed callback functions. timerFunc executes Promise. Promise is the syntax under es6. If the current environment only supports syntax under es6, we can only consider the later support.

Let me give you a deeper understanding of this.$nextTick!

  • 支持MutationObserver,HTML5的api,中文意思是:修改的监听,MutationObserver用来监听DOM的变动,比如节点的增减、属性的变动、文本内容的修改等都会触发MutationObserver事件。注意地,与事件不同,事件是同步触发,DOM的变动会立即触发事件,而MutationObserver事件是异步触发,DOM不会立即触发,需要等当前所有DOM操作完毕才会触发。

MutationObserver有7个属性:childList(true,监听子节点的变动)、attributes(true,监听属性的变动)、characterData(true,监听节点内容或节点文本的变动)、subtree(是否应用于该节点的所有后代节点)、attributeOldValue(观察attributes变动时,是否需要记录变动前的属性值)、characterDataOldValue(观察characterData变动时,是否需要记录变动前的值)、attributeFilter(数组,表示需要观察的特定属性(比如[‘class’,‘src’])。

为什么需要创建一个文本节点?因为在这里操作DOM保证浏览器页面是最新DOM渲染的,虽然看来好像是没什么作用,但这是保证拿到的DOM是最新的。

Let me give you a deeper understanding of this.$nextTick!

  • 支持setImmediatesetTimeout,setImmediate即时计时器立即执行工作,它是在事件轮询之后执行,为了防止轮询阻塞,每次只会调用一个。setTimeout按照一定时间后执行回调函数。

Let me give you a deeper understanding of this.$nextTick!

好了好了,到了现在,我们都知道nextTick做了什么吧,但是我们有没有想过这样的一个问题:既然都是异步回调执行等待DOM更新后才去调用操作DOM的代码,那么这个机制又是什么原理?这就是JS的执行机制有关了,涉及宏任务与微任务的知识,我们先来看看这样的一道题:

console.log(&#39;同步代码1&#39;);
setTimeout(function () {
    console.log("setTimeout");
}, 0);
new Promise((resolve) => {
    console.log(&#39;同步代码2&#39;)
    resolve()
}).then(() => {
    console.log(&#39;promise.then&#39;)
})
console.log(&#39;同步代码3&#39;);
Copy after login

我们可能会问上面的输出是个啥,首先js是单线程,所以在js程序运行中只有一个执行栈,实现不了多线程,所以就需要任务均衡分配,通俗的讲,按任务急优先处理原则,js中分为同步任务和异步任务,异步任务又分为宏任务和微任务,同步任务先入栈,程序会先把执行栈中的所有同步任务执行完,再去判断是否有异步任务,而异步任务中微任务的优先级高于宏任务。如果当前执行栈为空,而微任务队列不为空,就先执行微任务,等把所有微任务执行完,最后才会考虑宏任务。而上面代码中Promise是属于微任务,而setTimeout是宏任务,所以上面的输出为:

// 同步代码1
// 同步代码2
// 同步代码3
// promise.then 
// setTimeout
Copy after login

使用Vue2的nextTick

  • 传入回调函数参数使用:

    this.$nextTick(()=>{
      // ...操作DOM的代码
    })
    Copy after login
  • 不传入回调函数参数使用:

    // 方式一
    this.$nextTick().then(()=>{
      // ...操作DOM的代码
    })
    
    // 方式二
    await this.$nextTick();
    // 后写操作DOM的代码
    Copy after login

Vue3版本的nextTick

Vue3版本就没有Vue2版本的那么多环境支持,nextTick封装成了一个Promise异步回调函数执行。

// Vue3.2.45
// core-main\core-main\packages\runtime-core\src
export function nextTick<T = void>(
  this: T,
  fn?: (this: T) => void
): Promise<void> {
  const p = currentFlushPromise || resolvedPromise
  return fn ? p.then(this ? fn.bind(this) : fn) : p
}
Copy after login

使用Vue3的nextTick

  • 传入回调函数使用

    import { nextTick } from &#39;vue&#39; // 引入
    setup () {    
    nextTick(()=>{
       // ...操作DOM的代码
    })
    Copy after login
  • 不传入回调函数的使用

    import { nextTick } from &#39;vue&#39; // 引入
    setup () {    
        // 方式一
        nextTick().then(()=>{
          // ...操作DOM的代码
        })
    
        // 方式二
        await nextTick();
        // 后写操作DOM的代码
    }
    Copy after login

    总结

    • nextTick可以通俗的当作一个Promise,所以nextTick属于微任务。
    • nextTick在页面更新数据后,DOM更新,可以通俗理解为,nextTick就是用来支持操作DOM的代码及时更新渲染页面。也就是在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
    • 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。

    (学习视频分享:vuejs入门教程编程基础视频

    The above is the detailed content of Let me give you a deeper understanding of this.$nextTick!. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:juejin.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template