¿Por qué nextTick está en Vue?

Resumen: este artículo analizará el papel de nextTick, los escenarios de uso y el principio detrás de él, con la esperanza de ser útil para todos.

Este artículo es compartido por la comunidad HUAWEI CLOUD " ¿Cuál es el rol de nextTick en Vue? ", por CoderBin.

1. Qué sigueTick

Echemos un vistazo a la definición oficial de la misma:

Ejecuta la devolución de llamada diferida después de que finalice el siguiente ciclo de actualización de DOM. Utilice este método inmediatamente después de modificar los datos para obtener el DOM actualizado.

¿Qué significa eso?

Podemos entender que Vue se ejecuta de forma asíncrona al actualizar el DOM. Cuando los datos cambien, Vue abrirá una cola de actualización asincrónica, y la vista debe esperar a que se completen todos los cambios de datos en la cola y luego actualizarla de manera uniforme.

por ejemplo:

estructura html

<div id="app"> {{ message }} </div>

Construir una instancia vue

const vm = new Vue({
  el: '#app',
  data: {
    message: '原始值'
 }
})

Modificar mensaje

this.message = '修改后的值1' 
this.message = '修改后的值2' 
this.message = '修改后的值3'

En este momento, quiero obtener el último nodo DOM de la página, pero encuentro que se obtiene el valor anterior.

console.log(vm.$el.textContent) // 原始值

Esto se debe a que cuando los datos del mensaje cambian, vue no actualizará el Dom de inmediato, sino que colocará la operación de modificación de los datos en una cola de operación asíncrona.

Si seguimos modificando los mismos datos, la cola de operaciones asíncronas también se deduplicará

Después de esperar a que se completen todos los cambios de datos en el mismo bucle de eventos, se procesarán los eventos en la cola y se actualizará el DOM.

¿Por qué tener nexttick?

por ejemplo

{{num}} 
for(let i=0; i<100000; i++){ 
  num = i 
}

Si no hay un mecanismo de actualización nextTick, entonces cada vez que se actualice el valor de num, la vista se actualizará (el código anterior actualizará la vista 100,000 veces). Con el mecanismo nextTick, solo necesita actualizarse una vez, entonces nextTick es esencialmente una estrategia de optimización

2. Escenarios de uso

Si desea obtener la estructura DOM actualizada inmediatamente después de modificar los datos, puede usar Vue.nextTick()

  • El primer parámetro es: función de devolución de llamada (puede obtener la última estructura DOM)
  • El segundo parámetro es: el contexto de la función de ejecución.
// 修改数据
vm.message = '修改后的值'
// DOM 还没有更新
console.log(vm.$el.textContent) // 原始的值
Vue.nextTick(function () {
 // DOM 更新了
  console.log(vm.$el.textContent) // 修改后的值
})

El uso del método de instancia vm.$nextTick() en el componente solo necesita pasar this.$nextTick(), y esto en la función de devolución de llamada se vinculará automáticamente a la instancia actual de Vue

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
this.$nextTick(function () {
    console.log(this.$el.textContent) // => '修改后的值'
})

$nextTick() devolverá un objeto Promise, que se puede usar para lograr lo mismo con async/await

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
await this.$nextTick()
console.log(this.$el.textContent) // => '修改后的值'

3. Principio de realización

Ubicación del código fuente: /src/core/util/next-tick.js

callbacks es la cola de operaciones asincrónicas

Después de agregar la función de devolución de llamada, se ejecuta la función timerFunc.Pendiente se usa para identificar que el mismo tiempo solo se puede ejecutar una vez

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;
 });
 }
}

La definición de la función timerFunc, aquí es para determinar qué método llamar de acuerdo con qué método admite el entorno actual, respectivamente:

Promise.then、MutationObserver、setImmediate、setTimeout

Use cualquiera de los métodos anteriores para degradar

export let isUsingMicroTask = false
if (typeof Promise !== 'undefined' && isNative(Promise)) {
 //判断1:是否原生支持Promise
 const p = Promise.resolve()
 timerFunc = () => {
 p.then(flushCallbacks)
 if (isIOS) setTimeout(noop)
 }
 isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
 isNative(MutationObserver) ||
 MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
 //判断2:是否原生支持MutationObserver
 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
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
 //判断3:是否原生支持setImmediate
 timerFunc = () => {
 setImmediate(flushCallbacks)
 }
} else {
 //判断4:上面都不行,直接用setTimeout
 timerFunc = () => {
 setTimeout(flushCallbacks, 0)
 }
}

Ya sea una micro tarea o una macro tarea, se usará en flushCallbacks

Aquí, haga una copia de las funciones en las devoluciones de llamada y deje las devoluciones de llamada vacías.

Ejecutar las funciones en las devoluciones de llamada a su vez

function flushCallbacks () {
  pending = false
 const copies = callbacks.slice(0)
 callbacks.length = 0
 for (let i = 0; i < copies.length; i++) {
    copies[i]()
 }
}

Cuarto, el resumen final.

  1. Coloque la función de devolución de llamada en devoluciones de llamada para esperar la ejecución
  2. Poner la función de ejecución en la microtarea o macrotarea
  3. El evento se repite en la microtarea o macro tarea, y la función de ejecución ejecuta las devoluciones de llamada en las devoluciones de llamada a su vez.

 

Haga clic en Seguir para conocer las nuevas tecnologías de HUAWEI CLOUD por primera vez~

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4526289/blog/5584854
Recomendado
Clasificación