This is the third day of my participation in the August Text Challenge.More challenges in August

What is nextTick?

NextTick is essentially a hook that executes deferred callbacks, taking a callback function as an argument that executes deferred callbacks after the next DOM update loop ends. Use this method immediately after modifying the data to get the updated DOM. Starting with Vue 2.1.0, if no callback function is provided and in an environment that supports Promise, a Promise is returned. Note that the Vue itself does not come with polyfills; if the environment does not support Promise, you will need to provide polyfills yourself.

The role of nextTick

Speaking of nextTick, we also have to talk about the asynchronous update of the Vue, which is executed asynchronously when updating the DOM. As long as it listens for data changes, Vue opens a queue and buffers all data changes that occur in the same event loop. If the same watcher is triggered more than once, it will only be pushed into the queue once. This removal of duplicate data while buffering is important to avoid unnecessary computation and DOM manipulation. Then, in the next event loop, “TICK,” Vue refreshes the queue and performs the actual (de-duplicated) work. Vue (2.6.x) internally attempts to use native Promise.then, MutationObserver, and setImmediate for asynchronous queues, and setTimeout(fn, 0) is used instead if the execution environment does not support it.

For example, when you set vm.someData = ‘new value’, the component does not immediately re-render. When the queue is refreshed, the component is updated in the next event loop “TICK”. In most cases we don’t need to worry about this process, but if you want to do something based on the updated DOM state, it can be tricky. While vue.js generally encourages developers to think in a “data-driven” way and avoid direct contact with the DOM, sometimes we have to. To wait for Vue to finish updating the DOM after the data changes, use vue.nexttick (callback) immediately after the data changes. This callback will be called after the DOM update is complete.

In addition to allowing us to perform deferred callbacks after DOM updates, nextTick also uses nextTick internally in Vue to put DOM rendering operations into callbacks.

Why is nextTick the next tick?

A tick comes from the periodic interruption (output pulse) of a timer. Each interruption represents one tick, also known as a “clock tick.” The nextTick is literally the next tick of the clock, the next task. The next task, familiar from Event Loop, is a quick reminder of the Event Loop through an example.

Console. log(' sync code 1'); setTimeout(() => { console.log('setTimeout') }, 0) new Promise((resolve) => {console.log(' sync code 2') resolve()}).then(() => {console.log('promise.then')}) Console. log(' sync code 3'); // Final output "sync code 1"," sync code 2", "sync code 3", "promise.then", "setTimeout"Copy the code

Now that we know about the browser’s event loop mechanism, let’s go back to Vue nextTick. NextTick is a deferred callback that executes after the next DOM update cycle ends.

First tick (first step in the legend, ‘this update loop’)

  • First modify the data, which is a synchronization task. All synchronization tasks for the same event loop are executed on the main thread, forming a stack of executions, before DOM is involved.
  • Vue opens an asynchronous queue and buffers any data changes that occur in this event loop. If the same watcher is triggered more than once, it will only be pushed into the queue once.
  • The synchronization task is executed on the main thread, which is the first task.

Second tick (second step in the legend, ‘next update loop’)

  • When the synchronization task is complete, the asynchronous Watcher queue starts to execute tasks and update the DOM. Vue internally tries to use native promise.then and MO for asynchronous queues, and if the execution environment does not support it, setImmediate or setTimeout(fn, 0) instead (apis vary from Vue version to Vue version).
  • DOM update is the second task.

Third tick (third step in legend)

  • When the DOM update loop is complete, the next task execution is invoked, which is the delayed callback registered in nextTick. $nextTick is the same operation as the second task, but belongs to a different task.
  • The third task.

NextTick principle

The principle of nextTick can be summed up in one sentence as “using the Event loop Event thread to perform asynchronous operations.” Essentially, you register asynchronous tasks to process them. The difference is that the elegant downgrading of this asynchronous task is different in different versions of Vue.

A case in point

<div id="example">
   <span>{{test}}</span>
   <button @click="handleClick">change</button>
</div>
Copy the code
var vm = new Vue({
  el: '#example',
  data: { 
    test: 'begin',
  },
  methods: {
    handleClick: function() {
      this.test = 1;
      console.log('script')
      this.$nextTick(function () { 
        console.log('nextTick')
      });
      Promise.resolve().then(function () {
        console.log('promise')
      })
    }
  }
});
Copy the code

Vue 2.4 outputs script, nextTick, and Promise. NextTick execution order. Test source: link.

In Vue 2.5+, this code is output in script, Promise, and nextTick. Test source: link.

In Vue 2.6+, output script, nextTick, promise. While this is consistent with the output of Vue2.4, the internal implementation is different, as discussed later.

Note: The order of output here is not unique, but also related to API compatibility.

Look at the source code, the original very simple

The source code for nextTick is simple (sample screenshots: 2.6.11, 2.x are not much different here, but the timerFunc wrapper will be covered later), with just a few lines of code. The general steps are as follows:

The callbacks registered by the user are stored through the array Callbacks. The variable pending is declared to indicate whether a task is being executed. An asynchronous lock is used to wait for the task queue to complete before executing the next task. Set pending to true when the current task queue is in normal progress, and set pending to false when the task is completed. In this way, the pending value can be used to determine whether the current task queue is executing and whether the new task needs to be put into the next task queue. In the current queue, the function flushCallbacks is executed. When this function is fired, all the functions in the Callbacks are executed in sequence, then the callbacks are cleared, and pending is set to false. The flushCallbacks will only be executed once in an event loop. Note that the callback queue is backed up when the flushCallbacks function is executed. Because there is a situation where nextTick is also used in the callback function. If the flushCallbacks loop through the callback without special processing, the nextTick callback in the flushCallbacks will go directly to the callback queue.

The evolution of nextTick timerFunc

Prior to version 2.4

Pull the post-2.0 wrapper for timerFunc from Git in Vue and find that it was the same wrapper before 2.4. The graceful downgrade scheme is:

However, this solution, which has been shown to be problematic in later versions, can cause some weird problems due to the high execution priority of microTask, which can even bubble up faster than events in some scenarios. Such as:

Issues: the link

Version 2.5

A repackaging of timerFunc for pre-2.5 issues:

In version 2.5, microTask mixed with macroTask was elegantly demoted, but there were some problems with this scheme:

Issues: the link

Codepen. IO /ericcirone/… If you are interested, you can look at the source test code. The problem is that when the page switches back and forth at 1000px (greater than 1000, less than 1000), the list shows a flicker for 1s. Essentially the reason is that the preferential use of macroTask has a performance impact on some scenes that have been redrawn and animated, causing flicker.

Version 2.6

In order to address some historical issues in previous versions, nextTick eventually adopted a policy of defaulting to microTask and forcing macroTask to go for some DOM interaction events, such as the v-ON-bound event callback handler. There is also an elegant degradation at the source level, as follows:

conclusion

NextTick often appears in interviews. Interviewers usually test candidates through The Event Loop of nextTick or derive nextTick through the Event Loop. This article analyzes the principle of Vue nextTick from several aspects, and also peeps into the past and present life of nextTick from Vue upgrade version, hoping to help you reading.

That’s all for this article. Thanks for watching, and if you still like it, please give it a thumbs up. Thanks.

reference

  • Cn.vuejs.org/v2/api/#Vue…

  • github.com/vuejs/vue

  • Github.com/vuejs/vue/i…

  • Github.com/vuejs/vue/i…

  • Kaiwu.lagou.com/course/cour…

  • zhuanlan.zhihu.com/p/174396758

  • Note.youdao.com/web/#/file/…

  • Segmentfault.com/a/119000001…

  • Mp.weixin.qq.com/s/BoVNpttH8…

  • www.cnblogs.com/kelly-sunsh…

  • www.cnblogs.com/Joe-and-Joa…

  • Mp.weixin.qq.com/s/2Lu8REdTo…

  • Juejin. Im/post / 5 cd985…