Heim  >  Artikel  >  Web-Frontend  >  Eine kurze Analyse der Implementierungsmethode von Vue.nextTick

Eine kurze Analyse der Implementierungsmethode von Vue.nextTick

小云云
小云云Original
2018-01-03 11:17:001342Durchsuche

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 !== &#39;undefined&#39; && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => { console.error(err) }
  timerFunc = () => {
   p.then(nextTickHandler).catch(logError) // 重点
  }
 } else if (&#39;!isIE MutationObserver&#39;) {
  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 !== &#39;undefined&#39;) {
   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 !== &#39;undefined&#39;) {
   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 !== &#39;undefined&#39; && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => { console.error(err) }
  timerFunc = () => {
   p.then(nextTickHandler).catch(logError) // 重点
  }
 } else if (&#39;!isIE MutationObserver&#39;) {
  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, &#39;nextTick&#39;)
})

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, &#39;nextTick&#39;)
})

Schreiben Sie es direkt so.


const simpleNextTick = function queueNextTick (cb) {
  timerFunc = () => {
   return Promise.resolve().then(() => {
    cb()
   })
  }
  timerFunc()
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, &#39;nextTick&#39;)
})

Dieses Mal vereinfachen wir auch die selbstausführende Funktion


const simpleNextTick = function queueNextTick (cb) {
   return Promise.resolve().then(cb)
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, &#39;nextTick&#39;)
})

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: &#39;#example&#39;,
 data: {
  message: &#39;123&#39;
 }
})
vm.message = &#39;new message&#39; // 更改数据
vm.$el.textContent === &#39;new message&#39; // false
Vue.nextTick(function () {
 vm.$el.textContent === &#39;new message&#39; // 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, &#39;nextTick&#39;) // 也可以换成ajax请求
})


function sleep (ms) {
 return new Promise(resolve => setTimeout(resolve, ms) // 也可以换成ajax请求
}
async function oneTick (ms) {
 console.log(&#39;start&#39;)
 await sleep(ms)
 console.log(&#39;end&#39;)
}
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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn