1. What is ()?
The official documentation is explained as follows:
Delayed callback executed after the next DOM update loop ends. Use this method immediately after modifying the data to obtain the updated DOM.
2. Why use nextTick?
<!DOCTYPE html> <html> <head> <title>DemoVue</title> <script src="/vue/vue1/"></script> </head> <body> <div > <template> <div ref="list"> {{name}} </div> </template> </div> <script> new Vue({ el: '#app', data: { name: 'aa' }, mounted() { (); }, methods: { updateData() { var self = this; = 'bb'; (this.$); // aa this.$nextTick(function(){ (self.$); // bb }); } } }); </script> </body> </html>
As mentioned above, the bb is displayed on the page view, but when I print on the console, 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 = 'bb'; and then use (this.$); to print the value or aa? That's because after setting the value of name, the DOM has not been updated yet, so the 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. Therefore, after the DOM is updated, you can get the latest value by getting the element's value.
Understand DOM update: In VUE, when we modify a certain value in data, it will not be reflected immediately into the el. Vue places the changed data into an asynchronous queue of the watcher. The watcher queue task will only be executed when the current task is idle. This has a delay time, so after putting it into the nextTick function, you can get the latest value of the el. It is also OK if we change the nextTick above to setTimeout.
3. Detailed explanation of Vue source code nextTick (source code is vue/src/core/util/)
Before understanding the nextTick source code, let’s first understand the MutationObserver API added in html5. Its function is to monitor the interface for DOM changes. It can monitor the deletion of child nodes, modification of attributes, modification of text content, 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; /* The reason I want to copy a slice is because some cbs will add content to callbacks during execution, such as $nextTick's callback function has $nextTick. Then these should be put into the nextTick of the next round to execute, so copy it and traverse it to prevent it from continuing to loop. */ const copies = (0) = 0 for (let i = 0; i < ; i++) { copies[i]() } } // the nextTick behavior leverages the microtask queue, which can be accessed // via either native 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 behavior uses the microtask queue, first using ().then(nextTickHandler) to transfer the asynchronous callback Put it in microtask, both Promise and MutationObserver can be used, but MutationObserver is on IOS9.3 or above There are bugs in the WebView, so if the first item is met, it can be executed. If there is no native Promise, use MutationObserver. */ if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = () var logError = err => { (err) } timerFunc = () => { (nextTickHandler).catch(logError) // in problematic UIWebViews, doesn't completely break, but // it can get stuck in a weird state where callbacks are pushed into the // microtask queue but the queue isn't being flushed, until the browser // needs to do some other work, . 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 !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS () === '[object MutationObserverConstructor]' )) { // use MutationObserver where native Promise is not available, // . PhantomJS IE11, iOS7, Android 4.4 /* Create a MutationObserver, observe listens to the callback executed after the DOM changes nextTickHandler */ var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = (String(counter)); // Use MutationObserver interface to listen to the character content of text nodes (textNode, { characterData: true }); /* Each time the timerFunc function is executed, the content of the text node will be switched between 0/1. After the switch, it will be assigned to the text node that our MutationObserver listens to. */ timerFunc = () => { counter = (counter + 1) % 2 = String(counter) } } else { // fallback to setTimeout /* If neither of the above supports, we will use setTimeout to execute */ timerFunc = () => { setTimeout(nextTickHandler, 0) } } return function queueNextTick (cb?: Function, ctx?: Object) { let _resolve (() => { if (cb) { try { (ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }); /* If pending is true, it means that timerFunc(nextTickHandler, 0) */ if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve = resolve }) } } })()
Understanding the overall idea: First of all, nextTick is a closure function, and the code is executed immediately. Before understanding the overall code, let’s first look at a similar demo, as follows:
<!DOCTYPE html> <html> <head> <title>DemoVue</title> </head> <body> <div > </div> <script> var nextTick = (function(){ return function queueNextTick(cb, ctx) { if (cb) { try { (ctx) } catch (e) { ('What happened?'); } } } })(); // Method call nextTick(function(){ (2); // Print 2 }) </script> </body> </html>
The demo code is very similar to the above code.
We can also use nextTick to make demo code as follows:
var nextTick2 = (function(){ const callbacks = []; let pending = false; let timerFunc; function nextTickHandler () { pending = false const copies = (0) = 0 for (let i = 0; i < ; i++) { copies[i]() } } if (typeof Promise !== 'undefined') { var p = () var logError = err => { (err) } timerFunc = () => { (nextTickHandler).catch(logError) } } else if (typeof MutationObserver !== 'undefined' || // PhantomJS and iOS () === '[object MutationObserverConstructor]' ) { // use MutationObserver where native Promise is not available, // . PhantomJS IE11, iOS7, Android 4.4 var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = (String(counter)) (textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 = String(counter) } } else { // fallback to setTimeout /* istanbul ignore next */ timerFunc = () => { setTimeout(nextTickHandler, 0) } } return function queueNextTick (cb, ctx) { let _resolve (() => { if (cb) { try { (ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve = resolve }) } } })(); nextTick2(function(){ (2222); });
The above code is an extraction of nextTick source code. In order to better understand nextTick, the above demo was made.
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. For true, it means that the timeFunc function has been executed, and then define the nextTickHandler function. The function is to traverse the functions saved by the array callbacks in turn and execute in turn;
Please see the source code as follows:
function nextTickHandler () { pending = false const copies = (0) = 0 for (let i = 0; i < ; i++) { copies[i]() } }
Then there are three judgments, the code is as follows:
if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = (); var logError = err => { (err) } timerFunc = () => { (nextTickHandler).catch(logError); } else if (typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS () === '[object MutationObserverConstructor]' )){ var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = (String(counter)) (textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 = String(counter) } } else { timerFunc = () => { setTimeout(nextTickHandler, 0) } }
First, determine whether the Promise object is supported. If it is supported, define the timeFunc() function, prepare for the next call, and then continue to determine whether the object is supported. MutationObserver. If it is supported, create a text node to listen to whether the data of the node has changed. If it is changed, call the timerFunc function, and the counter value will be switched at 0/1. If the value changes, assign the data value to the data attribute. If the data attribute changes, the page will be re-rendered (because vue is used to listen to whether the attribute value has changed). If neither of the above situations are satisfied, then directly use setTimeout to execute the nextTickHandler function;
Finally, the nextTick code returns a function, the code is as follows:
return function queueNextTick (cb?: Function, ctx?: Object) { let _resolve (() => { if (cb) { try { (ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve = resolve }) } }
The meaning of the code is: whether the passed cb is a function, whether the ctx parameter is an object, if cb is a function, use (ctx), if timerFunc has not been executed, then pending is false, so the timerFunc() function is executed. This is the basic idea.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.