Table of Contents
1. NextTick quiz
2. NextTick source code implementation
1. Global variables
2. flushCallbacks
3. Asynchronous implementation of nextTick
4. nextTickMethod implementation
Home Web Front-end Vue.js Sharing useful information to help you understand Vue.nextTick in Vue

Sharing useful information to help you understand Vue.nextTick in Vue

Mar 22, 2022 am 11:37 AM
vue

This article will share with you Vue pure dry information and introduce you to Vue.nextTick that you don’t know. I hope it will be helpful to everyone!

Sharing useful information to help you understand Vue.nextTick in Vue

Friends who have used Vue will know it more or less$nextTick~ Before formally explaining nextTick, I think you should know Vue clearly When updating the DOM, it is executed asynchronously, because the next explanation process will be explained together with the component update~ Without further ado, let’s go straight to the topic (this article uses the v2.6.14 version Vue source code is explained) [Related recommendations: vuejs video tutorial]

1. NextTick quiz

Do you really understand nextTick? Come on, go directly to the question~

<template>
  <div id="app">
    <p ref="name">{{ name }}</p>
    <button @click="handleClick">修改name</button>
  </div>
</template>

<script>
  export default {
  name: &#39;App&#39;,
  data () {
    return {
      name: &#39;井柏然&#39;
    }
  },
  mounted() {
    console.log(&#39;mounted&#39;, this.$refs.name.innerText)
  },
  methods: {
    handleClick () {
      this.$nextTick(() => console.log(&#39;nextTick1&#39;, this.$refs.name.innerText))
      this.name = &#39;jngboran&#39;
      console.log(&#39;sync log&#39;, this.$refs.name.innerText)
      this.$nextTick(() => console.log(&#39;nextTick2&#39;, this.$refs.name.innerText))
    }
  }
}
</script>
Copy after login

In the above code, when clicks the button "Modify name", 'nextTick1', 'sync log' , 'nextTick2' corresponding this.$refs.name.innerText will output respectively? Note, what is printed here is the innerText of the DOM~ (the answer will be posted at the end of the article)

If you have a very firm answer at this time, then you don’t need to continue reading. Okay~ But if you have concerns about your answer, then you might as well follow me and read on. I believe that after reading it, you will have a definite answer without having to see the answer~!


2. NextTick source code implementation

The source code is located in core/util/next-tick. It can be divided into 4 parts and go directly to the code

1. Global variables

##callbacksQueue, pendingStatus

const callbacks = [] // 存放cb的队列
let pending = false // 是否马上遍历队列,执行cb的标志
Copy after login


2. flushCallbacks

Traverse callbacks to execute each cb

function flushCallbacks () {
  pending = false // 注意这里,一旦执行,pending马上被重置为false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]() // 执行每个cb
  }
}
Copy after login


3. Asynchronous implementation of nextTick

Adopt different asynchronous implementation strategies according to the degree of support of the execution environment

let timerFunc // nextTick异步实现fn

if (typeof Promise !== &#39;undefined&#39; && isNative(Promise)) {
  // Promise方案
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks) // 将flushCallbacks包装进Promise.then中
  }
  isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== &#39;undefined&#39; && (
  isNative(MutationObserver) ||
  MutationObserver.toString() === &#39;[object MutationObserverConstructor]&#39;
)) {
  // MutationObserver方案
  let counter = 1
  const observer = new MutationObserver(flushCallbacks) // 将flushCallbacks作为观测变化的cb
  const textNode = document.createTextNode(String(counter)) // 创建文本节点
  // 观测文本节点变化
  observer.observe(textNode, {
    characterData: true
  })
  // timerFunc改变文本节点的data,以触发观测的回调flushCallbacks
  timerFunc = () => { 
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  isUsingMicroTask = true
} else if (typeof setImmediate !== &#39;undefined&#39; && isNative(setImmediate)) {
  // setImmediate方案
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  // 最终降级方案setTimeout
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}
Copy after login

    Use a real statement here The case deepens the understanding of
  • MutationObserver. After all, compared to the other three asynchronous solutions, this one should be the most unfamiliar to everyone. <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>const observer = new MutationObserver(() =&gt; console.log(&amp;#39;观测到文本节点变化&amp;#39;)) const textNode = document.createTextNode(String(1)) observer.observe(textNode, { characterData: true }) console.log(&amp;#39;script start&amp;#39;) setTimeout(() =&gt; console.log(&amp;#39;timeout1&amp;#39;)) textNode.data = String(2) // 这里对文本节点进行值的修改 console.log(&amp;#39;script end&amp;#39;)</pre><div class="contentsignin">Copy after login</div></div>
  • Do you know what the corresponding output will be like?
    • script start, script end will be executed in the first round of macro tasks, this is no problem

    • setTimeout will be put into the next round of macro task execution

    • #MutationObserver is a micro task, so it will be executed after the current round of macro task Executed, so it precedes setTimeout

  • The result is as shown below:

  • Sharing useful information to help you understand Vue.nextTick in Vue

4. nextTickMethod implementation

cbPromisemethod

export function nextTick (cb?: Function, ctx?: Object) {
  let _resolve
  // 往全局的callbacks队列中添加cb
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, ctx, &#39;nextTick&#39;)
      }
    } else if (_resolve) {
      // 这里是支持Promise的写法
      _resolve(ctx)
    }
  })
  if (!pending) {
    pending = true
    // 执行timerFunc,在下一个Tick中执行callbacks中的所有cb
    timerFunc()
  }
  // 对Promise的实现,这也是我们使用时可以写成nextTick.then的原因
  if (!cb && typeof Promise !== &#39;undefined&#39;) {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}
Copy after login

    In-depth details , understand what
  • pending is used for and how it works?
Case 1, executed twice in the same round of Tick

$nextTick, timerFunc will only be executed once

this.$nextTick(() => console.log(&#39;nextTick1&#39;))
this.$nextTick(() => console.log(&#39;nextTick2&#39;))
Copy after login

    Is it more intuitive to use pictures?

Sharing useful information to help you understand Vue.nextTick in Vue


3. Asynchronous update of Vue components

If there is any componentization of Vue

, Distribution updateFor those who don’t know much about it, you can click here to see the illustrated Vue responsiveness principle Learn about Vue componentization and distribution updates and then come back~

Vue's

Asynchronous updateDOM is actually implemented using nextTick, which is actually the same $nextTick we usually use~

Here we review, when What happens when we change the value of an attribute?

Sharing useful information to help you understand Vue.nextTick in Vue

According to the distribution update process in the above figure, we start from the start of watcher.update, take

Rendering Watcher as an example, and enter queueWatcher

1. What did queueWatcher do?
// 用来存放Wathcer的队列。注意,不要跟nextTick的callbacks搞混了,都是队列,但用处不同~
const queue: Array<Watcher> = []

function queueWatcher (watcher: Watcher) {
  const id = watcher.id // 拿到Wathcer的id,这个id每个watcher都有且全局唯一
  if (has[id] == null) {
    // 避免添加重复wathcer,这也是异步渲染的优化做法
    has[id] = true
    if (!flushing) {
      queue.push(watcher)
    }
    if (!waiting) {
      waiting = true
      // 这里把flushSchedulerQueue推进nextTick的callbacks队列中
      nextTick(flushSchedulerQueue)
    }
  }
}
Copy after login

2. What did flushSchedulerQueue do?
function flushSchedulerQueue () {
  currentFlushTimestamp = getNow()
  flushing = true
  let watcher, id
  // 排序保证先父后子执行更新,保证userWatcher在渲染Watcher前
  queue.sort((a, b) => a.id - b.id)
  // 遍历所有的需要派发更新的Watcher执行更新
  for (index = 0; index < queue.length; index++) {
    watcher = queue[index]
    id = watcher.id
    has[id] = null
    // 真正执行派发更新,render -> update -> patch
    watcher.run()
  }
}
Copy after login

    Finally, a picture to understand the asynchronous update process of components

Sharing useful information to help you understand Vue.nextTick in Vue


4. Regression question I

believe that through the above analysis of nextTick source code, we have unveiled its mysterious veil. At this time, you must be able to tell the answer firmly. Without further ado, let’s check it out together and see if it’s what you think!

1、如图所示,mounted时候的innerText是“井柏然”的中文

Sharing useful information to help you understand Vue.nextTick in Vue

2、接下来是点击按钮后,打印结果如图所示

Sharing useful information to help you understand Vue.nextTick in Vue

  • 没错,输出结果如下(意不意外?惊不惊喜?)

    • sync log 井柏然

    • nextTick1 井柏然

    • nextTick2 jngboran

  • 下面简单分析一下每个输出:

    this.$nextTick(() => console.log(&#39;nextTick1&#39;, this.$refs.name.innerText))
    this.name = &#39;jngboran&#39;
    console.log(&#39;sync log&#39;, this.$refs.name.innerText)
    this.$nextTick(() => console.log(&#39;nextTick2&#39;, this.$refs.name.innerText))
    Copy after login
    • sync log:这个同步打印没什么好说了,相信大部分童鞋的疑问点都不在这里。如果不清楚的童鞋可以先回顾一下EventLoop,这里不多赘述了~

    • nextTick1:注意其虽然是放在$nextTick的回调中,在下一个tick执行,但是他的位置是在this.name = 'jngboran'的前。也就是说,他的cb会App组件的派发更新(flushSchedulerQueue)更先进入队列,当nextTick1打印时,App组件还未派发更新,所以拿到的还是旧的DOM值。

    • nextTick2就不展开了,大家可以自行分析一下。相信大家对它应该是最肯定的,我们平时不就是这样拿到更新后的DOM吗?

  • 最后来一张图加深理解

  • Sharing useful information to help you understand Vue.nextTick in Vue


    写在最后,nextTick其实在Vue中也算是比较核心的一个东西了。因为贯穿整个Vue应用的组件化、响应式的派发更新与其息息相关~深入理解nextTick的背后实现原理,不仅能让你在面试的时候一展风采,更能让你在日常开发工作中,少走弯路少踩坑!好了,本文到这里就暂告一段落了,如果读完能让你有所收获,就帮忙点个赞吧~画图不易、创作艰辛鸭~

    (学习视频分享:vuejs教程web前端

    The above is the detailed content of Sharing useful information to help you understand Vue.nextTick in Vue. For more information, please follow other related articles on the PHP Chinese website!

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

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to use bootstrap in vue How to use bootstrap in vue Apr 07, 2025 pm 11:33 PM

Using Bootstrap in Vue.js is divided into five steps: Install Bootstrap. Import Bootstrap in main.js. Use the Bootstrap component directly in the template. Optional: Custom style. Optional: Use plug-ins.

How to add functions to buttons for vue How to add functions to buttons for vue Apr 08, 2025 am 08:51 AM

You can add a function to the Vue button by binding the button in the HTML template to a method. Define the method and write function logic in the Vue instance.

How to reference js file with vue.js How to reference js file with vue.js Apr 07, 2025 pm 11:27 PM

There are three ways to refer to JS files in Vue.js: directly specify the path using the &lt;script&gt; tag;; dynamic import using the mounted() lifecycle hook; and importing through the Vuex state management library.

How to use watch in vue How to use watch in vue Apr 07, 2025 pm 11:36 PM

The watch option in Vue.js allows developers to listen for changes in specific data. When the data changes, watch triggers a callback function to perform update views or other tasks. Its configuration options include immediate, which specifies whether to execute a callback immediately, and deep, which specifies whether to recursively listen to changes to objects or arrays.

What does vue multi-page development mean? What does vue multi-page development mean? Apr 07, 2025 pm 11:57 PM

Vue multi-page development is a way to build applications using the Vue.js framework, where the application is divided into separate pages: Code Maintenance: Splitting the application into multiple pages can make the code easier to manage and maintain. Modularity: Each page can be used as a separate module for easy reuse and replacement. Simple routing: Navigation between pages can be managed through simple routing configuration. SEO Optimization: Each page has its own URL, which helps SEO.

How to return to previous page by vue How to return to previous page by vue Apr 07, 2025 pm 11:30 PM

Vue.js has four methods to return to the previous page: $router.go(-1)$router.back() uses &lt;router-link to=&quot;/&quot; component window.history.back(), and the method selection depends on the scene.

How to query the version of vue How to query the version of vue Apr 07, 2025 pm 11:24 PM

You can query the Vue version by using Vue Devtools to view the Vue tab in the browser's console. Use npm to run the "npm list -g vue" command. Find the Vue item in the "dependencies" object of the package.json file. For Vue CLI projects, run the "vue --version" command. Check the version information in the &lt;script&gt; tag in the HTML file that refers to the Vue file.

How to use vue traversal How to use vue traversal Apr 07, 2025 pm 11:48 PM

There are three common methods for Vue.js to traverse arrays and objects: the v-for directive is used to traverse each element and render templates; the v-bind directive can be used with v-for to dynamically set attribute values ​​for each element; and the .map method can convert array elements into new arrays.

See all articles