Implement asynchronous update queue through nextTick() in Vuejs
This article mainly introduces the source code analysis of nextTick() asynchronous update queue in Vuejs. Now I will share it with you and give you a reference.
vue official website explains this as follows:
In-depth responsive principle of asynchronous update queue in vue2.0
The official website explains as follows:
As long as Upon observing data changes, Vue will open a queue and buffer all data changes that occur in the same event loop. If the same watcher is triggered multiple times, it will only be pushed into the queue once. This deduplication during buffering is important to avoid unnecessary calculations and DOM operations. Then, on the next event loop "tick", Vue flushes the queue and performs the actual (deduplicated) work. Vue internally tries to use native Promise.then and MutationObserver for asynchronous queues. If the execution environment does not support it, setTimeout(fn, 0) will be used instead.
For example, when you set vm.someData = 'new value' , the component will not re-render immediately. When the queue is flushed, the component is updated on the next "tick" when the event loop queue is cleared. Most of the time we don't need to worry about this process, but if you want to do something after the DOM state is updated, it can be a bit tricky. While Vue.js generally encourages developers to think in a "data-driven" way and avoid touching the DOM directly, there are times when we really need to do that. To wait for Vue to finish updating the DOM after the data changes, you can use Vue.nextTick(callback) immediately after the data changes. This callback function will be called after the DOM update is completed. For example
Source code analysis
The method prototype and analysis comments are as follows:
var nextTick = (function () { var callbacks = []; // 存储需要触发的回调函数 var pending = false; // 是否正在等待的标识(false:允许触发在下次事件循环触发callbacks中的回调, true: 已经触发过,需要等到下次事件循环) var timerFunc; // 设置在下次事件循环触发callbacks的 触发函数 //处理callbacks的函数 function nextTickHandler () { pending = false;// 可以触发timeFunc var copies = callbacks.slice(0);//复制callback callbacks.length = 0;//清空callback for (var i = 0; i < copies.length; i++) { copies[i]();//触发callback回调函数 } } //如果支持Promise,使用Promise实现 if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); var logError = function (err) { console.error(err); }; timerFunc = function () { p.then(nextTickHandler).catch(logError); // ios的webview下,需要强制刷新队列,执行上面的回调函数 if (isIOS) { setTimeout(noop); } }; //如果Promise不支持,但是支持MutationObserver(h5新特性,异步,当dom变动是触发,注意是所有的dom都改变结束后触发) } else if (typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' )) { // use MutationObserver where native Promise is not available, // e.g. PhantomJS IE11, iOS7, Android 4.4 var counter = 1; var observer = new MutationObserver(nextTickHandler); //创建一个textnode dom节点,并让MutationObserver 监视这个节点;而 timeFunc正是改变这个dom节点的触发函数 var textNode = document.createTextNode(String(counter)); observer.observe(textNode, { characterData: true }); timerFunc = function () { counter = (counter + 1) % 2; textNode.data = String(counter); }; } else {// 上面两种不支持的话,就使用setTimeout timerFunc = function () { setTimeout(nextTickHandler, 0); }; } //nextTick接受的函数, 参数1:回调函数 参数2:回调函数的执行上下文 return function queueNextTick (cb, ctx) { var _resolve;//用于接受触发 promise.then中回调的函数 //向回调数据中pushcallback callbacks.push(function () { //如果有回调函数,执行回调函数 if (cb) { cb.call(ctx); } if (_resolve) { _resolve(ctx); }//触发promise的then回调 }); if (!pending) {//是否执行刷新callback队列 pending = true; timerFunc(); } //如果没有传递回调函数,并且当前浏览器支持promise,使用promise实现 if (!cb && typeof Promise !== 'undefined') { return new Promise(function (resolve) { _resolve = resolve; }) } } })();
I explained the logic of the nextTick() function in the comments
The reason why the above three ways of handling callbacks use priority: because Promise and MutationObserver are in the same event loop as the triggered event (but they are just running in the micro queue), but the setTimeout callback function is running under inside the time loop.
The reason for using Promise first is that MutationObserver stops after running for a period of time in UIWebview of ios9.3.3 or above.
The comments in the above code have fully explained the code logic. Simple understanding: push the callback into the queue. If it has not been executed yet, the callback function will be triggered during the next event loop execution.
Note: If you use nextTick() without setting the callback function, but use Promise to set the callback function, this does not point to the current Vue instance, but to the window (strict mode is undefined);
But from the above analysis, we can know that the execution context is passed through the first parameter of the callback function in Promise.then().
Where nextTick() is used
1. It is a function of global Vue, so we can call it directly through vue.
2. In the Vue system, operations used to process dom updates
There is a watcher in Vue, which is used to observe changes in data and then update the dom. We knew earlier that not every data change in Vue will trigger an update to the dom. Instead, these operations are cached in a queue. After an event loop ends, the queue is refreshed and the dom update operation is performed uniformly.
function queueWatcher (watcher) { var id = watcher.id; if (has[id] == null) { has[id] = true; if (!flushing) { queue.push(watcher); } else { // if already flushing, splice the watcher based on its id // if already past its id, it will be run next immediately. var i = queue.length - 1; while (i >= 0 && queue[i].id > watcher.id) { i--; } queue.splice(Math.max(i, index) + 1, 0, watcher); } // queue the flush if (!waiting) { waiting = true; nextTick(flushSchedulerQueue); } } }
Briefly explain the logic of the above code, because it is the code of the watcher and will be analyzed later. The function of nextTick() here is to refresh the dom update operation checked by the watcher at the end of this event loop.
3. Partial Vue triggers $nextTick() and executes the corresponding logic after the dom is updated.
Vue.prototype.$nextTick = function (fn) { return nextTick(fn, this)// 设置nextTick回调函数的上下文环境是当前Vue实例 };
The above is a piece of code in renderMinxin, which is the code for initializing the render module.
Summary
If we don’t understand its code, we will have misunderstandings.
1. nextTick() will not redraw the current page, and it will not be executed until the page is redrawn, but will definitely be executed after the event loop ends.
2. The triggering of this method is not executed after the page update is completed. The first item has already been mentioned, but why can the updated data be obtained in this method? That is because the attributes of the dom element have been It changed when the watcher executed the flush queue, so it can be obtained at this time.
Examples that prove the above point of view:
h5 has a method requestFrameAnimation(callback). The callback of this method is called before the page is redrawn. Through experimentation, when updating the dom, nextTick() is executed before this method.
The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.
Related articles:
How to dynamically load data using treeview in the Bootstrap framework
About website generation chapter directory code example
Detailed introduction to Vue data binding
The above is the detailed content of Implement asynchronous update queue through nextTick() in Vuejs. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

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

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

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.

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.

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.

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.

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

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

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.

There are two ways to jump div elements in Vue: use Vue Router and add router-link component. Add the @click event listener and call this.$router.push() method to jump.
