In diesem Artikel wird hauptsächlich die Implementierungsmethode von Vue.nextTick vorgestellt. Dies ist eine Quellcodeanalyse der vue.nextTick-API-Implementierung nach der Ereignisschleife und MicroTask. Der Herausgeber findet es ziemlich gut, deshalb möchte ich es jetzt mit Ihnen teilen und es als Referenz für alle zur Verfügung stellen. Folgen wir dem Herausgeber und schauen wir uns das an. Ich hoffe, es kann allen helfen.
Vorheizen und eine Schlaffunktion schreiben
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)
Erklären Sie die Schlaffunktion
Wann Wenn die asynchrone Funktion „await PromiseFn()“ ausführt, wird die Ausführung der Funktion angehalten. Wir wissen auch, dass PromiseFn jetzt innerhalb der microTask ausgeführt wird. Wenn die MicroTask nicht ausgeführt wurde, wird die nachfolgende MacroTask nicht ausgeführt. Über die Ereignisschleifenfunktion von MicroTask haben wir außerdem eine Schlaffunktion implementiert, die die Ausführung von console.log
Process
verhindert
1 Console.log('start') ausführen
2 Wait ausführen Die Ausführung wird angehalten und wartet darauf, dass PromiseFn nach der Wait-Funktion in microTask ausgeführt wird.
3 In der Sleep-Funktion Verzögerung in ms, um zurückzukehren
4 Führen Sie nach der Rückkehr zur Auflösung console.log('end') aus
nextTick API
So verwenden Sie nextTick vue
vue.nextTick(() => { // todo... })
Nachdem Sie die Verwendung verstanden haben, werfen Sie einen Blick auf den Quellcode
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 }) } } })() // 自执行函数
Wenn Sie sich den Quellcode kurz ansehen, können Sie verstehen, dass die nextTick-API eine selbstausführende Funktion ist
Da es sich um eine selbstausführende Funktion handelt, schauen Sie sich direkt ihren Rückgabetyp an, die Rückgabefunktion 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 }) } }
Konzentrieren Sie sich nur auf die Funktion queueNextTick des Hauptprozesses und drücken Sie die von uns übergebene () => ... } in Rückrufe
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) // 重点 } }
In diesem Absatz sehen wir die drei markierten Punkte, die angeben, dass Promise, MutationObserver oder setTimeout(fn, 0) zur Ausführung verwendet werden nextTickHandler in verschiedenen Browserumgebungen
function nextTickHandler () { pending = false const copies = callbacks.slice(0) // 复制 callbacks.length = 0 // 清空 for (let i = 0; i < copies.length; i++) { copies[i]() // 逐个执行 } }
nextTickHandler dient dazu, das () auszuführen, das wir in Rückrufe vor => { // todo... } in den aktuellen Aufgaben einfügen.
Schreiben Sie einen einfachen nextTick
Der Quellcode kann kompliziert sein, daher schreiben wir selbst einen einfachen 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') })
Wir können hier sehen, dass das Prinzip von nextTick darin besteht, ein Versprechen zurückzugeben, und unser Todo-Code wird in diesem Versprechen ausgeführt. Jetzt können wir weiter vereinfachen
const simpleNextTick = (function () { return function queueNextTick (cb) { timerFunc = () => { return Promise.resolve().then(() => { cb() }) } timerFunc() } })() simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
Schreiben Sie es direkt so.
const simpleNextTick = function queueNextTick (cb) { timerFunc = () => { return Promise.resolve().then(() => { cb() }) } timerFunc() } simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
Dieses Mal vereinfachen wir auch die selbstausführende Funktion
const simpleNextTick = function queueNextTick (cb) { return Promise.resolve().then(cb) } simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
Jetzt vereinfachen wir es Direkt am Ende habe ich festgestellt, dass der Kerninhalt von nextTick Promise ist, eine Mikroaufgabe.
Jetzt kehren wir zum offiziellen Beispiel der nextTick API von vue zurück
<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 })
Es stellt sich heraus, dass nach der Aktualisierung der Daten in Vue die Dom-Aktualisierung erfolgt Dies erfolgt in der nächsten, später ausgeführten Ereignisschleife.
Das Prinzip der Verwendung von nextTick besteht hauptsächlich darin, das Szenario zu lösen, in dem DOM unmittelbar nach der Aktualisierung der Daten in einem einzigen Ereignis betrieben wird.
Da wir nun wissen, dass der Kern von nextTick MicroTasks verwendet, vergleichen wir zunächst das vereinfachte nextTick mit der Sleep-Funktion.
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)
Wir sehen, dass die Ausführungsergebnisse von nextTick und oneTick, die wir geschrieben haben, so ähnlich sind. Der einzige Unterschied besteht darin, dass nextTick den Rückruf mit einem Promise umschließt, ihn zurückgibt und ausführt, während oneTick „await“ verwendet, um eine Promise-Funktion auszuführen, und dieses Promise über eine eigene umschlossene Webapi-Funktion verfügt.
Können wir bei einer Ajax-Anfrage direkt Axios verwenden, um die Promise-Bibliothek zurückzugeben
async function getData () { const data = await axios.get(url) // 操作data的数据来改变dom return data }
Dies kann auch das gleiche Ergebnis wie nextTick erzielen Die Rolle von
Schließlich können wir dem Quellcode auch entnehmen, dass Sie MutationObserver oder setTimeout(cb, 0) verwenden können, um den gleichen Effekt zu erzielen, wenn die Browserumgebung Promise nicht unterstützt. Aber der letzte Kern ist microTask
Verwandte Empfehlungen:
Verwendungsbeispiele von Process.nextTick in Node.js
Knoten Analyse des Unterschieds zwischen Timer nextTick() und setImmediate() in .js_node.js
Verwendungsbeispiel von process.nextTick in Node.js_node.js
Das obige ist der detaillierte Inhalt vonEine kurze Analyse der Implementierungsmethode von Vue.nextTick. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!