Home Web Front-end JS Tutorial Detailed explanation of nextTick function source code in Vue

Detailed explanation of nextTick function source code in Vue

Jan 15, 2018 pm 04:53 PM
nexttick function Detailed explanation

This article mainly introduces the source code analysis of the nextTick function in Vue. The editor thinks it is quite good, so I will share it with you now and give it as a reference. Let’s follow the editor to take a look, I hope it can help everyone.

1. What is Vue.nextTick()?

The official document explains as follows:

A delayed callback executed after the next DOM update cycle ends. Use this method immediately after modifying the data to get the updated DOM.

2. Why use nextTick?


<!DOCTYPE html>
<html>
 <head>
 <title>演示Vue</title>
 <script src="https://tugenhua0707.github.io/vue/vue1/vue.js"></script>
 </head>
 <body>
 <p id="app">
  <template>
  <p ref="list">
   {{name}}
  </p>
  </template>
 </p>
 <script>
  new Vue({
  el: &#39;#app&#39;,
  data: {
   name: &#39;aa&#39;
  },
  mounted() {
   this.updateData();
  },
  methods: {
   updateData() {
   var self = this;
   this.name = &#39;bb&#39;;
   console.log(this.$el.textContent); // aa
   this.$nextTick(function(){
    console.log(self.$el.textContent); // bb
   });
   }
  }
  });
 </script>
 </body>
</html>
Copy after login

The above code displays bb on the page view, but when I log in to the console When printing, the text content obtained is still aa, but after using nextTick, the text content obtained is the latest content bb, so in this case, we can use the nextTick function.

Why does the above code change this.name = 'bb'; and then use console.log(this.$el.textContent); to print the value still aa? That's because after setting the value of name, the DOM has not been updated, so the obtained value is still the previous value. However, when we put it in the nextTick function, the code will be executed after the DOM is updated, so after the DOM is updated, the element is obtained again. The latest value can be obtained.

Understand DOM updates: In VUE, when we modify a value in the data, it will not be immediately reflected in the el. Vue will put the changed data into an asynchronous queue of the watcher. , the watcher queue task will only be executed when the current task is idle, which has a delay time, so after placing it in the nextTick function, the latest value of the el can be obtained. It is also possible if we change the nextTick above to setTimeout.

3. Detailed explanation of Vue source code nextTick (the source code is in vue/src/core/util/env.js)

Before understanding the nextTick source code, let’s understand it first The following is the new MutationObserver API in HTML5. Its function is to monitor DOM changes. It can monitor the deletion of child nodes, attribute modifications, text content modifications, etc. of a DOM object.

nextTick source code is as follows:


export const nextTick = (function () {
 const callbacks = []
 let pending = false
 let timerFunc

 function nextTickHandler () {
 pending = false;
 /*
  之所以要slice复制一份出来是因为有的cb执行过程中又会往callbacks中加入内容,比如$nextTick的回调函数里又有$nextTick,
  那么这些应该放入到下一个轮次的nextTick去执行,所以拷贝一份,遍历完成即可,防止一直循环下去。
  */
 const copies = callbacks.slice(0)
 callbacks.length = 0
 for (let i = 0; i < copies.length; i++) {
  copies[i]()
 }
 }

 // the nextTick behavior leverages the microtask queue, which can be accessed
 // via either native Promise.then or MutationObserver.
 // MutationObserver has wider support, however it is seriously bugged in
 // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
 // completely stops working after triggering a few times... so, if native
 // Promise is available, we will use it:
 /* istanbul ignore if */
 /*
 nextTick行为利用了microtask队列, 先使用 Promise.resolve().then(nextTickHandler)来将异步回调
 放入到microtask中,Promise 和 MutationObserver都可以使用,但是 MutationObserver 在IOS9.3以上的
 WebView中有bug,因此如果满足第一项的话就可以执行,如果没有原生Promise就用 MutationObserver。
 */
 if (typeof Promise !== &#39;undefined&#39; && isNative(Promise)) {
 var p = Promise.resolve()
 var logError = err => { console.error(err) }
 timerFunc = () => {
  p.then(nextTickHandler).catch(logError)
  // in problematic UIWebViews, Promise.then doesn&#39;t completely break, but
  // it can get stuck in a weird state where callbacks are pushed into the
  // microtask queue but the queue isn&#39;t being flushed, until the browser
  // needs to do some other work, e.g. handle a timer. Therefore we can
  // "force" the microtask queue to be flushed by adding an empty timer.
  if (isIOS) setTimeout(noop)
 }
 } else if (typeof MutationObserver !== &#39;undefined&#39; && (
 isNative(MutationObserver) ||
 // PhantomJS and iOS 7.x
 MutationObserver.toString() === &#39;[object MutationObserverConstructor]&#39;
 )) {
 // use MutationObserver where native Promise is not available,
 // e.g. PhantomJS IE11, iOS7, Android 4.4
 /*
  创建一个MutationObserver,observe监听到DOM改动之后执行的回调 nextTickHandler 
  */
 var counter = 1
 var observer = new MutationObserver(nextTickHandler)
 var textNode = document.createTextNode(String(counter));
 // 使用MutationObserver的接口,监听文本节点的字符内容
 observer.observe(textNode, {
  characterData: true
 });
 /*
  每次执行timerFunc函数都会让文本节点的内容在0/1之间切换,切换之后将新赋值到那个我们MutationObserver监听的文本节点上去。
  */
 timerFunc = () => {
  counter = (counter + 1) % 2
  textNode.data = String(counter)
 }
 } else {
 // fallback to setTimeout
 /*
  如果上面的两种都不支持的话,我们就使用setTimeout来执行
  */
 timerFunc = () => {
  setTimeout(nextTickHandler, 0)
 }
 }

 return function queueNextTick (cb?: Function, ctx?: Object) {
 let _resolve
 callbacks.push(() => {
  if (cb) {
  try {
   cb.call(ctx)
  } catch (e) {
   handleError(e, ctx, &#39;nextTick&#39;)
  }
  } else if (_resolve) {
  _resolve(ctx)
  }
 });
 /* 如果pending为true,表明本轮事件循环中已经执行过 timerFunc(nextTickHandler, 0) */
 if (!pending) {
  pending = true
  timerFunc()
 }
 if (!cb && typeof Promise !== &#39;undefined&#39;) {
  return new Promise((resolve, reject) => {
  _resolve = resolve
  })
 }
 }
})()
Copy after login

Understanding of the overall idea: First, nextTick is a closure function, and the code is executed immediately, before understanding the overall code , let’s first look at a similar demo, the following code:


<!DOCTYPE html>
<html>
 <head>
 <title>演示Vue</title>
 </head>
 <body>
 <p id="app">
  
 </p>
 <script>
  var nextTick = (function(){
  return function queueNextTick(cb, ctx) {
   if (cb) {
   try {
    cb.call(ctx)
   } catch (e) {
    console.log(&#39;出错了&#39;);
   }
   }
  }
  })();

  // 方法调用
  nextTick(function(){
  console.log(2); // 打印2
  })
 </script>
 </body>
</html>
Copy after login

The demo code is very similar to the above code.

We can also extract and use nextTick to make demo code as follows:


var nextTick2 = (function(){
 const callbacks = [];
 let pending = false;
 let timerFunc;

 function nextTickHandler () {
 pending = false
 const copies = callbacks.slice(0)
 callbacks.length = 0
 for (let i = 0; i < copies.length; i++) {
  copies[i]()
 }
 }
 if (typeof Promise !== &#39;undefined&#39;) {
 var p = Promise.resolve()
 var logError = err => { console.error(err) }
 timerFunc = () => {
  p.then(nextTickHandler).catch(logError)
 }
 } else if (typeof MutationObserver !== &#39;undefined&#39; ||
 // PhantomJS and iOS 7.x
 MutationObserver.toString() === &#39;[object MutationObserverConstructor]&#39;
 ) {
 // use MutationObserver where native Promise is not available,
 // e.g. PhantomJS IE11, iOS7, Android 4.4
 var counter = 1
 var observer = new MutationObserver(nextTickHandler)
 var textNode = document.createTextNode(String(counter))
 observer.observe(textNode, {
  characterData: true
 })
 timerFunc = () => {
  counter = (counter + 1) % 2
  textNode.data = String(counter)
 }
 } else {
 // fallback to setTimeout
 /* istanbul ignore next */
 timerFunc = () => {
  setTimeout(nextTickHandler, 0)
 }
 }
 return function queueNextTick (cb, ctx) {
 let _resolve
 callbacks.push(() => {
  if (cb) {
  try {
   cb.call(ctx)
  } catch (e) {
   handleError(e, ctx, &#39;nextTick&#39;)
  }
  } else if (_resolve) {
  _resolve(ctx)
  }
 })
 if (!pending) {
  pending = true
  timerFunc()
 }
 if (!cb && typeof Promise !== &#39;undefined&#39;) {
  return new Promise((resolve, reject) => {
  _resolve = resolve
  })
 }
 }
})();
nextTick2(function(){
 console.log(2222);
});
Copy after login

The above code is extracted from the nextTick source code, for better I understand nextTick and made the above demo.

Let’s understand the meaning of the overall code;

First define the array callbacks = []; to store all callback functions that need to be executed, and define let pending = false ; Determine whether the timerFunc(nextTickHandler, 0) function has been executed in this round of events. If it is true, it means that the timeFunc function has been executed. Then define the nextTickHandler function. The function of this function is to traverse the functions saved in the array callbacks in sequence and execute them in sequence;

Please see the source code as follows:


function nextTickHandler () {
 pending = false
 const copies = callbacks.slice(0)
 callbacks.length = 0
 for (let i = 0; i < copies.length; i++) {
 copies[i]()
 }
}
Copy after login

Then there are three judgments, the code is as follows:


if (typeof Promise !== &#39;undefined&#39; && isNative(Promise)) {
 var p = Promise.resolve();
 var logError = err => { console.error(err) }
 timerFunc = () => {
 p.then(nextTickHandler).catch(logError);
} else if (typeof MutationObserver !== &#39;undefined&#39; && (
 isNative(MutationObserver) ||
 // PhantomJS and iOS 7.x
 MutationObserver.toString() === &#39;[object MutationObserverConstructor]&#39;
)){
 var counter = 1
 var observer = new MutationObserver(nextTickHandler)
 var textNode = document.createTextNode(String(counter))
 observer.observe(textNode, {
 characterData: true
 })
 timerFunc = () => {
 counter = (counter + 1) % 2
 textNode.data = String(counter)
 }
} else {
 timerFunc = () => {
 setTimeout(nextTickHandler, 0)
 }
}
Copy after login

First determine whether the Promise object is supported. If so, define the timeFunc() function to prepare for the next call. Then continue to determine whether the object MutationObserver is supported. If so, create a text node and monitor the node data. Whether it has changed. If so, call the timerFunc function and the counter value will switch between 0/1. If the value changes, assign the data value to the data attribute. Then if the data attribute changes, it will be re-rendered. page (because vue monitors whether the property value changes through Object.defineProperty), if the above two conditions are not satisfied, then directly use setTimeout to execute the nextTickHandler function;

Finally nextTick code Return a function, the code is as follows:


return function queueNextTick (cb?: Function, ctx?: Object) {
 let _resolve
 callbacks.push(() => {
 if (cb) {
  try {
  cb.call(ctx)
  } catch (e) {
  handleError(e, ctx, &#39;nextTick&#39;)
  }
 } else if (_resolve) {
  _resolve(ctx)
 }
 })
 if (!pending) {
 pending = true
 timerFunc()
 }
 if (!cb && typeof Promise !== &#39;undefined&#39;) {
 return new Promise((resolve, reject) => {
  _resolve = resolve
 })
 }
}
Copy after login

The meaning of the code is: whether the incoming cb is a function, whether the ctx parameter is an object, if cb is a function, Using cb.call(ctx), if timerFunc has not been executed, then pending is false, so the timerFunc() function is executed. The basic idea is this.

Related recommendations:

A brief analysis of the implementation method of Vue.nextTick

process in Node.js .nextTick usage example

Difference analysis of timer nextTick() and setImmediate() in node.js_node.js

The above is the detailed content of Detailed explanation of nextTick function source code 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

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

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)

Tips for dynamically creating new functions in golang functions Tips for dynamically creating new functions in golang functions Apr 25, 2024 pm 02:39 PM

Go language provides two dynamic function creation technologies: closure and reflection. closures allow access to variables within the closure scope, and reflection can create new functions using the FuncOf function. These technologies are useful in customizing HTTP routers, implementing highly customizable systems, and building pluggable components.

Considerations for parameter order in C++ function naming Considerations for parameter order in C++ function naming Apr 24, 2024 pm 04:21 PM

In C++ function naming, it is crucial to consider parameter order to improve readability, reduce errors, and facilitate refactoring. Common parameter order conventions include: action-object, object-action, semantic meaning, and standard library compliance. The optimal order depends on the purpose of the function, parameter types, potential confusion, and language conventions.

How to write efficient and maintainable functions in Java? How to write efficient and maintainable functions in Java? Apr 24, 2024 am 11:33 AM

The key to writing efficient and maintainable Java functions is: keep it simple. Use meaningful naming. Handle special situations. Use appropriate visibility.

Complete collection of excel function formulas Complete collection of excel function formulas May 07, 2024 pm 12:04 PM

1. The SUM function is used to sum the numbers in a column or a group of cells, for example: =SUM(A1:J10). 2. The AVERAGE function is used to calculate the average of the numbers in a column or a group of cells, for example: =AVERAGE(A1:A10). 3. COUNT function, used to count the number of numbers or text in a column or a group of cells, for example: =COUNT(A1:A10) 4. IF function, used to make logical judgments based on specified conditions and return the corresponding result.

Comparison of the advantages and disadvantages of C++ function default parameters and variable parameters Comparison of the advantages and disadvantages of C++ function default parameters and variable parameters Apr 21, 2024 am 10:21 AM

The advantages of default parameters in C++ functions include simplifying calls, enhancing readability, and avoiding errors. The disadvantages are limited flexibility and naming restrictions. Advantages of variadic parameters include unlimited flexibility and dynamic binding. Disadvantages include greater complexity, implicit type conversions, and difficulty in debugging.

What are the benefits of C++ functions returning reference types? What are the benefits of C++ functions returning reference types? Apr 20, 2024 pm 09:12 PM

The benefits of functions returning reference types in C++ include: Performance improvements: Passing by reference avoids object copying, thus saving memory and time. Direct modification: The caller can directly modify the returned reference object without reassigning it. Code simplicity: Passing by reference simplifies the code and requires no additional assignment operations.

What is the difference between custom PHP functions and predefined functions? What is the difference between custom PHP functions and predefined functions? Apr 22, 2024 pm 02:21 PM

The difference between custom PHP functions and predefined functions is: Scope: Custom functions are limited to the scope of their definition, while predefined functions are accessible throughout the script. How to define: Custom functions are defined using the function keyword, while predefined functions are defined by the PHP kernel. Parameter passing: Custom functions receive parameters, while predefined functions may not require parameters. Extensibility: Custom functions can be created as needed, while predefined functions are built-in and cannot be modified.

C++ Function Exception Advanced: Customized Error Handling C++ Function Exception Advanced: Customized Error Handling May 01, 2024 pm 06:39 PM

Exception handling in C++ can be enhanced through custom exception classes that provide specific error messages, contextual information, and perform custom actions based on the error type. Define an exception class inherited from std::exception to provide specific error information. Use the throw keyword to throw a custom exception. Use dynamic_cast in a try-catch block to convert the caught exception to a custom exception type. In the actual case, the open_file function throws a FileNotFoundException exception. Catching and handling the exception can provide a more specific error message.

See all articles