nextTick

Official explanation – Defer the callback until after the next DOM update cycle. Use the data immediately after you modify it, and then wait for DOM updates. Execute asynchronously, called as early as possible in the next event loop

Macro or Micro?

Without considering compatibility, what is the implementation of nextTick? Depending on the source code from different eras, there are different answers.

Which are macro/micro tasks?
Macro task Micro tasks
setTimeout process.nextTick
setInterval MutationObserver
setImmediate Promise.then
requestAnimationFrame
MessageChannel

The iteration

In fact, nextTick has been tweaked several times in various versions of Vue’s evolution for various rendering and DOM event issues. Macro/micro tasks, or even both in parallel. Stabilized to microtasks in the latest version 2.6.12. In order to explore the specific reasons, as well as the problems encountered, I looked through multiple versions of the source code to find the answer.

V2.0.0 – v2.4.4 microtasks

At first, in Vue2.0, it was all microtasks based on MutationObserver or Promise processing. In ios >= 9.3.3, the MutationObserver had a strange lag bug in webViews. So use promises in preference. The following diagrams are all source screenshots of Vue, with the path in the first line of the diagram.

Problems arising

The priority of microtasks is so high that vUE rendering can be sandwiched between events bubbling or multiple consecutive events.

issues – #4521 #6690 #6566

Here I use the classic #6566 to illustrate the problem.

<div v-if="show">
    <i @click="show = false">show is true</i>
</div>
<div v-else @click="show = true">
    <i>show is false</i>
</div>
Copy the code

In fact, when you click on the I tag, you’ll always see show is true. Because the two DOM elements controlled by V-IF have the same structure, VUE reuses the elements to unbind and bind events on their parent. Due to the high priority of microtasks, the event bubbled up onto the div with @click=”show = true” attached, causing the state to change back. So you can always just see show is true.

V2.5.0 – V2.5.1 Macro tasks

In order to solve the above problems, it was changed to a full macro task in this release. Choose to use setImmediate and MessageChannel preferentially. SetTimeout even if setTimeout is set to setTimeout(fn, 0), according to the standard, there will be a minimum delay, generally 4ms. SetImmediate and MessageChannel, on the other hand, are immediately inserted into the macro task.

Problems arising

The macro task was too slow, causing animations and page state transitions to take too long to render.

#6813 has a list, CSS controls to display it vertically at 1000px, and V-show controls to listen for page width changes and hide the list at 1000px. Although the v-show state has been set to false due to the use of macro tasks, the redrawing of the DOM by Vue is not in the same event loop as the redrawing of CSS and is later. Therefore, the page will appear two backflow effects of the list first displayed vertically and then hidden, resulting in the screen flickering.

V2.5.2 – V2.5.20 micromacro parallelism

Therefore, the parallel strategy of microtask and macro task is adopted here. By default, the microtask is performed, and only the macro task is performed when the bound event function is executed. WitchMacroTask is called when an event is bound, causing the event function to execute the macro task.


A problem

However, the problem comes again, the following is due to the event all walk macro tasks caused by the problem that cannot be solved, interested in a closer look. Personally, I understand that it is mainly caused by the protection measures for user privacy on ios system. I hope someone can give detailed answers.

#7109 #7153 #7546 #7834 #8109

V2.6.0 – V2.6.12 microtasks

It eventually reverted back to the walking task, but with some changes to the event execution. In order to prevent the function execution caused by the high priority of microtasks in some cases discovered earlier.