Heim > Web-Frontend > js-Tutorial > Hauptteil

Detaillierte Erläuterung der Implementierungsmethode von Vue.nextTick

小云云
Freigeben: 2018-01-22 10:06:36
Original
1369 Leute haben es durchsucht

In diesem Artikel wird hauptsächlich die Implementierungsmethode von Vue.nextTick vorgestellt. Der Herausgeber findet sie recht gut, daher werde ich sie jetzt mit Ihnen teilen und als Referenz verwenden. Folgen wir dem Herausgeber und schauen wir uns das an. Ich hoffe, es kann allen helfen.

Dies ist eine Quellcode-Analyse der vue.nextTick-API-Implementierung nach Ereignisschleife und MicroTask.

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)
Nach dem Login kopieren

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...
})
Nach dem Login kopieren

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
   })
  }
 }
})() // 自执行函数
Nach dem Login kopieren

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
   })
  }
 }
Nach dem Login kopieren

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) // 重点
  }
 }
Nach dem Login kopieren

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]() // 逐个执行
  }
 }
Nach dem Login kopieren

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;)
})
Nach dem Login kopieren

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;)
})
Nach dem Login kopieren

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;)
})
Nach dem Login kopieren

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;)
})
Nach dem Login kopieren

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
})
Nach dem Login kopieren

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请求
})
Nach dem Login kopieren


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)
Nach dem Login kopieren

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
}
Nach dem Login kopieren

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:

Detaillierte Erklärung von Vue + Vuex mit der vm.$nextTick-Instanz

Ausführliche Erläuterung des Quellcodes der nextTick-Funktion in Vue

Verwendungsbeispiele von process.nextTick in Node.js

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Implementierungsmethode von Vue.nextTick. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
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
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage