Cet article présente principalement la méthode d'implémentation de Vue.nextTick. Il s'agit d'une analyse du code source de l'implémentation de l'API vue.nextTick après la boucle d'événements et MicroTask. L’éditeur le trouve plutôt bien, alors j’aimerais le partager avec vous maintenant et le donner comme référence pour tout le monde. Suivons l'éditeur pour y jeter un œil, j'espère que cela pourra aider tout le monde.
Préchauffer et écrire une fonction veille
function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms) } async function oneTick (ms) { console.log('start') await sleep(ms) console.log('end') } oneTick(3000)
Expliquez la fonction veille
Quand la fonction asynchrone exécute wait PromiseFn(), l'exécution de la fonction est suspendue. Nous savons également que PromiseFn est désormais exécutée au sein de la microTask. Lorsque la microTask n'a pas été exécutée, la macroTask suivante ne sera pas exécutée. Nous avons également implémenté une fonction de veille via la fonction de boucle d'événements de microTask, empêchant l'exécution de console.log
Process
.
1 Exécuter console.log('start')
2 Exécuter wait, l'exécution est en pause, attendre que le PromiseFn après la fonction wait soit exécuté dans microTask
3 Dans la fonction sleep, retarder ms pour revenir
4 Après être revenu pour résoudre, exécutez console.log('end')
API nextTick
Comment utiliser nextTick dans vue
vue.nextTick(() => { // todo... })
Après avoir compris l'utilisation, jetez un œil au code source
const nextTick = (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 !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) // 重点 } } else if ('!isIE MutationObserver') { var counter = 1 var observer = new MutationObserver(nextTickHandler) // 重点 var textNode = document.createTextNode(string(conter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } } else { timerFunc = () => { setTimeout(nextTickHandler, 0) // 重点 } } return function queueNextTick (cb, ctx) { // api的使用方式 let _resolve callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { err } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve =resolve }) } } })() // 自执行函数
En regardant brièvement le code source, vous pouvez comprendre que l'API nextTick est une fonction auto-exécutable
Puisqu'il s'agit d'une fonction auto-exécutable, regardez directement son type de retour, retournez la fonction queueNextTick ( cb, ctx) {...}
return function queueNextTick (cb, ctx) { // api的使用方式 let _resolve callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { err } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve =resolve }) } }
Concentrez-vous uniquement sur la fonction queueNextTick du processus principal et appuyez sur le () que nous avons passé => ... } dans les rappels
if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) // 重点 } } else if ('!isIE MutationObserver') { var counter = 1 var observer = new MutationObserver(nextTickHandler) // 重点 var textNode = document.createTextNode(string(conter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } } else { timerFunc = () => { setTimeout(nextTickHandler, 0) // 重点 } }
Dans ce paragraphe on peut voir les trois points marqués indiquant que Promise, MutationObserver ou setTimeout(fn, 0) sont utilisés pour exécuter nextTickHandler dans différents environnements de navigateur
function nextTickHandler () { pending = false const copies = callbacks.slice(0) // 复制 callbacks.length = 0 // 清空 for (let i = 0; i < copies.length; i++) { copies[i]() // 逐个执行 } }
nextTickHandler consiste à exécuter le () que nous avons mis dans les rappels avant => { // todo... } dans les tâches en cours.
Écrivez un simple nextTick
Le code source peut être compliqué, nous écrivons donc nous-mêmes un simple nextTick
const simpleNextTick = (function () { let callbacks = [] let timerFunc return function queueNextTick (cb) { callbacks.push(() => { // 给callbacks 推入cb() cb() }) timerFunc = () => { return Promise.resolve().then(() => { const fn = callbacks.shift() fn() }) } timerFunc() // 执行timerFunc,返回到是一个Promise } })() simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
Nous pouvons voir d'ici que le principe de nextTick est de renvoyer une promesse, et notre code todo est exécuté dans cette promesse. Nous pouvons maintenant continuer à simplifier
const simpleNextTick = (function () { return function queueNextTick (cb) { timerFunc = () => { return Promise.resolve().then(() => { cb() }) } timerFunc() } })() simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
const simpleNextTick = function queueNextTick (cb) { timerFunc = () => { return Promise.resolve().then(() => { cb() }) } timerFunc() } simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
const simpleNextTick = function queueNextTick (cb) { return Promise.resolve().then(cb) } simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
<p id="example">{{message}}</p> var vm = new Vue({ el: '#example', data: { message: '123' } }) vm.message = 'new message' // 更改数据 vm.$el.textContent === 'new message' // false Vue.nextTick(function () { vm.$el.textContent === 'new message' // true })
Le principe d'utilisation de nextTick est principalement de résoudre le scénario d'exploitation du DOM immédiatement après la mise à jour des données en un seul événement.
const simpleNextTick = function queueNextTick (cb) { return Promise.resolve().then(cb) } simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') // 也可以换成ajax请求 })
function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms) // 也可以换成ajax请求 } async function oneTick (ms) { console.log('start') await sleep(ms) console.log('end') } oneTick(3000)
async function getData () { const data = await axios.get(url) // 操作data的数据来改变dom return data }
Exemples d'utilisation de process.nextTick dans Node.js
node Analyse de la différence entre timer nextTick() et setImmediate() dans .js_node.js
Exemple d'utilisation de process.nextTick dans Node.js_node.js
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!