Le contenu de cet article concerne l'analyse de la méthode nextTick dans Vue2.6). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Une brève analyse de la méthode nextTick dans Vue 2.6.
Event Loop
La Event Loop et la Task Queue de JS sont en fait la clé pour comprendre le concept de nextTick.
Il existe en fait de nombreux articles de haute qualité sur Internet qui le présentent en détail, je vais donc le parcourir brièvement.
Le contenu suivant s'applique au JS côté navigateur. Le mécanisme de boucle d'événements de NodeJS est différent. Le cahier des charges
stipule que les tâches sont divisées en deux catégories : task(macrotask)
et microtask
.
Généralement considéré comme la source de la quête de task
:
setTimeout / setInterval setImmediate MessageChannel I/O UI rendering
Généralement considéré comme la source de la quête de microtask
:
Promise process.nextTick MutationObserver Object.observe(已废弃)
Aperçu simple : (voici les spécifications officielles)
Démarrez d'abordl'exécution du script de script jusqu'à ce que la pile de contexte d'exécution soit vide, puis commencez à effacer les tâches et les files d'attente dans lefile d'attente des microtâches Eh bien, premier entré, premier sorti, chacun est exécuté l'un après l'autre. Après l'effacement, parcourez la boucle des événements.
Boucle d'événements : récupérez en continu une tâche dans la file d'attente des tâches et placez-la sur la pile pour exécution, puis exécutez-la dans le courant loop Effacez les tâches dans la file d'attente des microtâches dans l'ordre. Après l'effacement, le rendu de la mise à jour de la page peut être déclenché (déterminé par le navigateur). Répétez les étapes de la
boucle d'événement.
nextTick
Le rendu mis à jour des modifications de données dans Vue vers DOM est un processus asynchrone.
Cette méthode est utilisée pour exécuter un rappel retardé après la fin de la boucle de mise à jour du DOM.
La méthode d'utilisation est très simple :
// 修改数据 vm.msg = 'Hello'; // DOM 还没有更新 Vue.nextTick(function() { // DOM 更新了 }); // 作为一个 Promise 使用 Vue.nextTick().then(function() { // DOM 更新了 });
Le code source, sans commentaires, ne comporte en réalité que moins d'une centaine de lignes, et le tout reste très simple à comprendre.
Ceci est divisé en 3 parties.
Présente les modules introduits et les variables définies.
// noop 空函数,可用作函数占位符 import { noop } from 'shared/util'; // Vue 内部的错误处理函数 import { handleError } from './error'; // 判断是IE/IOS/内置函数 import { isIE, isIOS, isNative } from './env'; // 使用 MicroTask 的标识符 export let isUsingMicroTask = false; // 以数组形式存储执行的函数 const callbacks = []; // nextTick 执行状态 let pending = false; // 遍历函数数组执行每一项函数 function flushCallbacks() { pending = false; const copies = callbacks.slice(0); callbacks.length = 0; for (let i = 0; i < copies.length; i++) { copies[i](); } }
Vient ensuite la fonction de retard asynchrone de base. Les stratégies adoptées par les différentes versions de Vue ici sont en réalité différentes. La version
2.6 préfère utiliser microtask comme wrapper différé asynchrone. La version
2.5 est une macrotâche combinée avec une microtâche. Cependant, il existe des problèmes mineurs lorsque l'état change avant le redessinage (comme #6813). De plus, l'utilisation de macrotask dans un gestionnaire d'événements peut conduire à un comportement étrange qui ne peut être contourné (comme #7109, #7153, #7546, #7834, #8109).
Donc, la version 2.6 utilise désormais à nouveau microtask Pourquoi ? . Parce que 2.4 et les versions antérieures utilisent également microtask. . . La
microtâche sera également problématique dans certains cas, car la microtâche a une priorité plus élevée et l'événement se produira dans la séquence des événements (comme #4521, # 6690) solution de contournement) se déclenche même pendant le bouillonnement du même événement (#6566).
// 核心的异步延迟函数,用于异步延迟调用 flushCallbacks 函数 let timerFunc; // timerFunc 优先使用原生 Promise // 原本 MutationObserver 支持更广,但在 iOS >= 9.3.3 的 UIWebView 中,触摸事件处理程序中触发会产生严重错误 if (typeof Promise !== 'undefined' && isNative(Promise)) { const p = Promise.resolve(); timerFunc = () => { p.then(flushCallbacks); // IOS 的 UIWebView,Promise.then 回调被推入 microtask 队列但是队列可能不会如期执行。 // 因此,添加一个空计时器“强制”执行 microtask 队列。 if (isIOS) setTimeout(noop); }; isUsingMicroTask = true; // 当原生 Promise 不可用时,timerFunc 使用原生 MutationObserver // 如 PhantomJS,iOS7,Android 4.4 // issue #6466 MutationObserver 在 IE11 并不可靠,所以这里排除了 IE } else if ( !isIE && typeof MutationObserver !== 'undefined' && (isNative(MutationObserver) || // PhantomJS 和 iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]') ) { let counter = 1; const observer = new MutationObserver(flushCallbacks); const textNode = document.createTextNode(String(counter)); observer.observe(textNode, { characterData: true, }); timerFunc = () => { counter = (counter + 1) % 2; textNode.data = String(counter); }; isUsingMicroTask = true; // 如果原生 setImmediate 可用,timerFunc 使用原生 setImmediate } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { timerFunc = () => { setImmediate(flushCallbacks); }; } else { // 最后的倔强,timerFunc 使用 setTimeout timerFunc = () => { setTimeout(flushCallbacks, 0); }; }
Résumé des priorités en une phrase : priorité des microtâches .
Promesse > MutationObserver > setImmediate > setTimeout
fonction nextTick
fonction nextTick. Accepte deux paramètres :
fonction de rappel cb : est la fonction à retarder
ctx : Spécifiez le this de la fonction de rappel cb vers lequel pointer
La méthode d'instance Vue $nextTick est encapsulée en outre, et ctx est défini sur l'instance Vue actuelle.
export function nextTick(cb?: Function, ctx?: Object) { let _resolve; // cb 回调函数会经统一处理压入 callbacks 数组 callbacks.push(() => { if (cb) { // 给 cb 回调函数执行加上了 try-catch 错误处理 try { cb.call(ctx); } catch (e) { handleError(e, ctx, 'nextTick'); } } else if (_resolve) { _resolve(ctx); } }); // 执行异步延迟函数 timerFunc if (!pending) { pending = true; timerFunc(); } // 当 nextTick 没有传入函数参数的时候,返回一个 Promise 化的调用 if (!cb && typeof Promise !== 'undefined') { return new Promise(resolve => { _resolve = resolve; }); } }
Résumé
En regardant l'ensemble, cela semble relativement facile à comprendre ~ 2.6 La version 2.6 est un peu plus simple qu'avant.
Pour résumer, ce qui sera fait à chaque fois que Vue.nextTick(cb)
est appelé :
la fonction cb est traitée et poussée dans le tableau de rappels , et le la fonction timerFunc est exécutée , retarde l'appel de la fonction flushCallbacks , et parcourt et exécute toutes les fonctions du tableau de rappels .
La priorité des appels retardés est la suivante :
Promise > MutationObserver > 🎜>Différences de version
En fait, les stratégies nextTick des versions
Vue 2.4, 2.5, 2.6sont légèrement différent. Globalement, 2,6 et
2,4 sont relativement similaires. (Regardez de plus près, c'est fondamentalement la même chose. 2.6 timerFunc a un ensemble supplémentaire de jugement immédiat) 2.5 La version est en fait similaire. . . Le code source est écrit un peu différemment. La priorité globale est : Promise > setImmediate > la mise à jour est déclenchée dans le gestionnaire d'événements v-on, nextTick utilisera d'abord la macrotâche.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!