[JavaScript] setTimeout, Promise, asíncrono / orden de ejecución Await (fino)


Nota: Este artículo entorno de tiempo de ejecución para la versión actual de Google Chrome (72.0.3626.109)

Recientemente vimos las preguntas cara frontal sobre un bucle tal caso:

//请写出输出内容
async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
	console.log('async2');
}

console.log('script start');

setTimeout(function() {
    console.log('setTimeout');
}, 0)

async1();

new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

salida:

script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

Esta pregunta se hace principalmente en el orden de ejecución de la función de bucle de eventos, incluyendo asíncrono, esperan, setTimeout, la función promesa. Esto es lo que esta pregunta involucrado en los puntos de conocimiento.

concepto de cola de tareas

En primer lugar, tenemos que entender lo siguiente:

  • JS divide en tareas síncronas y asíncronas de tareas
  • tareas de sincronización se ejecutan en el hilo principal para formar una pila de ejecución
  • Fuera del hilo principal, el evento disparado por hilo gestiona una cola de tareas, siempre que los ejecutan tareas asíncronas con los resultados, se coloca en un evento de cola de trabajos
  • Una vez que toda la ejecución simultánea de tareas completadas pila (JS motor en vacío en este momento), el sistema lee se añadirá la cola de tareas a la tareas asíncronas corriendo pila ejecutable, comenzó

De acuerdo con la especificación, el bucle de eventos es ser coordinados a través del mecanismo de la cola de tareas. Evento Loop una, puede haber una o más colas tareas (cola de tareas), una cola de tareas es una colección de tareas ordenadas (tarea), y cada tarea tiene una tarea fuente (fuente tarea), derivado de la misma tarea a fuente tarea debe ser colocado en la misma cola de tareas, que venir de diferentes fuentes se añadieron a diferentes colas. setTimeout / Promise y otra API es el origen de la tarea, en la cola de tareas es sus tareas específicas asignadas

Aquí Insertar imagen Descripción

ciclo de eventos (bucle de eventos)

El concepto:
JS principal ciclo constante hilo de la lectura de la tarea cola de tareas, realizar tareas, que administra el mecanismo de bucle de eventos llamada (bucle de eventos).

Nota:
Cada bucle de eventos tiene una cola microtask
para cada ciclo de eventos tienen una o (también puede llamarse cola de tareas) más macrotaks cola de
una tarea de trabajo se puede poner en cola macrotask microtask cola en
cada ciclo de eventos se realizó primera cola microtask, después de la ejecución es completa, extraer una tarea macrotask cola para unirse a la cola microtask, y luego continuar microtask cola, con el fin de realizar todas las tareas continúan hasta el final de la ejecución.

tarea macro (macrotareas)

El concepto:
(Macro) Tarea (también conocido como tarea macro), se entiende que cada ejecución de la pila de código es una macro para realizar tareas (incluyendo cada una, una pila de ejecución de devolución de llamada y el evento en la ejecución de la cola de eventos)

Proceso:
navegador para ser capaz de hacer que las tareas de trabajo y DOM (macro) internos JS para ser ejecutados secuencialmente, será al final de un (macro) ejecución de la tarea, la siguiente tarea (macro) para realizar antes del inicio del proceso de la página re-renderizado como sigue:

(Macro) de tareas -> 渲染 -> tarea (macro) -> ...

API:
(Macro) Tarea incluye principalmente: la escritura (todo el código), setTimeout, setInterval, I / O, la interfaz de usuario eventos de interacción, postMessage, MessageChannel, setImmediate (medio ambiente Node.js)

  • macrotareas
    setTimeout
    setImmerdiate
    setInterval
    I / O
    de interfaz de usuario渲染

Micro-tarea (microtareas)

El concepto:
Microtask (también conocido como micro-tarea), se entiende que las tareas realizadas inmediatamente después del final de la ejecución de la tarea actual. Es decir, antes de que la tarea actual después de la tarea, la tarea siguiente, antes de la representación.

Proceso:
Por lo que su velocidad de respuesta en comparación con setTimeout (setTimeout es una tarea) será más rápido, porque sin esperar a que la representación. Esto es, en cierto macrotask ejecutados, todos microtask se generará durante su ejecución se completó (antes de la representación)

(Macro) de tareas -> (micro) de tareas -> 渲染 -> tarea (macro) -> ...

API:
Microtask incluye principalmente: Promise.then, MutaionObserver, process.nextTick (medio ambiente Node.js)

  • microtareas
    process.nextTick
    promesa
    Object.observe (废弃)
    MutationObserver

mecanismo de funcionamiento

En el bucle de eventos, una vez para cada ciclo de funcionamiento se llama tic, tic cada modelo de procesamiento de la tarea es más compleja, pero los pasos claves son como sigue:

  • Ejecutar una tarea macro (no sólo obtener de la pila cola de eventos)
  • Si se encuentra durante la ejecución de tareas micro, que se añadirá a la cola de trabajos de micro-tarea
  • Después de que la tarea es terminada macro, micro aplicación inmediata de todas las tareas de los actuales micro-tareas en la cola (de ejecución de órdenes)
  • tarea macro actual está terminado, empezar a comprobar render, a continuación, hacer que el hilo de interfaz gráfica de usuario para hacerse cargo
  • Después de la representación es completa, hilo JS continúa para hacerse cargo, en el comienzo de una tarea macro (tomado de la cola de eventos)

Diagrama de flujo es el siguiente:
Aquí Insertar imagen Descripción

Promesa de asíncrono y ejecución inmediata

Sabemos que en el asíncrona Promise encarnan la captura y luego, por lo que escribir en código Promise se ejecuta como una tarea sincronizada inmediatamente. En asíncrono / esperan, antes de que aparezca aguardan emergencia con el código se ejecuta inmediatamente. Entonces no se lo esperan cuando sucedió?

esperan ser lo que se ha hecho

Desde el punto de vista esperar el significado literal es esperar, esperar lo esperan es una expresión, la expresión del valor de retorno puede ser un objeto de la promesa también puede haber otros valores.

Mucha gente piensa que después de la expresión aguardan esperar después de la ejecución continuará detrás del código es en realidad esperan una señal para dejar un hilo. esperamos la última expresión, primero realizará de nuevo, esperará detrás del código en microtask, y luego va a saltar de toda la función asíncrona para ejecutar el código detrás

revisión:

Porque como asíncrono esperan en sí prometen + generador de azúcar sintáctico . Por lo tanto esperar código detrás microtask. Dicha modificación puede estar presente por el primer título de que se trate a cabo:

async function async1() {
	console.log('async1 start');
	await async2();
	console.log('async1 end');
}

equivalente a

async function async1() {
	console.log('async1 start');
	Promise.resolve(async2()).then(() => {
                console.log('async1 end');
        })
}

El análisis de esta cuestión

Por encima de todo el conocimiento pertinente sobre cuestiones relacionadas con este, Volvamos a esta pregunta mirada paso a paso en cómo los niños.

  1. En primer lugar, el bucle de eventos de la cola de tareas macro (macrotask) comenzó, esta vez, la cola de tareas macro, sólo una secuencia de comandos (Código de conjunto) misión, cuando se enfrentan a la fuente de la tarea (origen de la tarea), entregará a cabo la tarea a la tarea que corresponde cola. Por lo tanto, el primer paso en el ejemplo anterior se lleva a cabo como se muestra a continuación:
    Aquí Insertar imagen Descripción

  2. Luego vimos primero definimos la función de dos asíncrono, a continuación, mirar hacia abajo, las declaraciones de la consola entonces conocido, arranque directo script de salida. Después de la salida, la tarea de secuencia de comandos para continuar hacia abajo, setTimeout encontrado, como una fuente de trabajo macro, que distribuirá su primera misión a la cola correspondiente:
    Aquí Insertar imagen Descripción

  3. Tarea secuencia de comandos para continuar por la implementación de la función Async1 (), dicho código de función anterior asíncrono es inmediatamente antes de la ejecución esperan, será inmediatamente salida de arranque Async1.

    Cuando esperan ser encontrados, se esperará a la expresión que realiza de nuevo, por lo que async2 Inmediatamente después de ejecutarse, entonces lo esperan código posterior se console.log('async1 end')añade a la cola de microtask promesa, luego de vuelta código de función para ejecutar Async1:
    Aquí Insertar imagen Descripción

  4. Continuar por la ejecución de la tarea de la escritura, se reunió ejemplo promesa. Promise Dado que la función se ejecuta inmediatamente, y la .then posterior será distribuida a la cola de microtask Promise. En primer promise1 de salida, a continuación, ejecutar la resolución, asignado a la correspondiente cola de promise2:
    Aquí Insertar imagen Descripción

  5. Tarea secuencia de comandos para continuar hacia abajo, y finalmente sólo una salida del fin de la escritura, hasta el momento, ha terminado la tarea global.

    De acuerdo con lo anterior, después de cada acabado ejecutar una tarea macro será comprobar si hay microtareas, si es así, hasta que los microtareas ejecución vacían Microtask Queue.

    Así, la tarea después de que el guión está terminado, empezar a buscar para el vaciado de cola de tareas micro. En este momento, la micro-tarea, Promise dos colas algunas tareas Async1 extremo y promise2, por lo tanto de acuerdo con el extremo de salida Async1 orden, promise2. Cuando todos terminaron microtareas, que representa la primera ronda del ciclo ha terminado.

  6. La segunda ronda es todavía el comienzo del ciclo de la cola de tareas macro. En este punto la tarea macro en solamente un setTimeout, salida directa se puede sacar, con lo que los extremos de todo el proceso.

Ahora voy a cambiar el código para impresionar.

Una variante de la fórmula

En una primera variante de la fórmula I también son un código de función Promise función async2 convertido es como sigue:

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
    //async2做出如下更改:
    new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
    });
}
console.log('script start');

setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();

new Promise(function(resolve) {
    console.log('promise3');
    resolve();
}).then(function() {
    console.log('promise4');
});

console.log('script end');

Se puede ver por sí mismo lo primero sería la secuencia de salida, vamos a la publicación de los resultados:

script start
async1 start
promise1
promise3
script end
promise2
async1 end
promise4
setTimeout

Después se ejecuta la primera macrotask, es decir, después del final script de salida, irá a limpiar toda microtask. Tendrá un promise2 de salida, fin Async1, promise4, el resto no más decir

Variant di (deformación)

En una segunda variante, que esperará más adelante en Async1 y async2 código se cambian de forma asíncrona, como sigue:

async function async1() {
    console.log('async1 start');
    await async2();
    //更改如下:
    setTimeout(function() {
        console.log('setTimeout1')
    },0)
}
async function async2() {
    //更改如下:
	setTimeout(function() {
		alert('setTimeout2')
	},0)
}
console.log('script start');

setTimeout(function() {
    console.log('setTimeout3');
}, 100)
async1();

new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

estructura de salida:

script start
async1 start
promise1
script end
promise2
(执行setTimeout2对应的逻辑,此时为阻断式,只有用户交互确认后再执行下面的定时器)
setTimeout1
setTimeout3

Después de la salida es promise2, el próximo será en secuencia de salida en el orden SetTimeOut unirse a la cola, por el principio del código ponemos el fin de la cola es setTimeout3 -> setTimeout2 -> setTimeout1, cuando la ejecución se lleva a cabo de forma secuencial, pero no está a la espera de un temporizador implementada dentro junto temporizador de ejecución, esta vez para ver quién es quién debe realizar salidas, esta vez puede ser conocido por el código setTimeout2 -> setTimeout1se ejecuta inmediatamente, con el fin de realizar setTimeout2, pero la lógica aquí es de denegación de alerta, por lo sólo el extremo de la interacción, continuará con el resto de los temporizadores, la salida secuencialmente pasado el tiempo de acuerdo a la temporizaciónsetTimeout1 -> setTimeout3

variante de tres

Tercera variante, veo una cara neutraliza el título original, en general muy similar, de la siguiente manera:

async function a1 () {
    console.log('a1 start')
    await a2()
    console.log('a1 end')
}
async function a2 () {
    console.log('a2')
}

console.log('script start')

setTimeout(() => {
    console.log('setTimeout')
}, 0)

Promise.resolve().then(() => {
    console.log('promise1')
})

a1()

let promise2 = new Promise((resolve) => {
    resolve('promise2.then')
    console.log('promise2')
})

promise2.then((res) => {
    console.log(res)
    Promise.resolve().then(() => {
        console.log('promise3')
    })
})
console.log('script end')

Nada más que hacer la tarea en una pieza de micro artículo secundario puntos, si se encuentra en frente de los contenidos leer las palabras Esta pregunta se hace sin duda no hay problema, también puede ser modificado aquí:

let promise2 = new Promise((resolve) => {
    resolve('promise2.then')
    console.log('promise2')
})

promise2.then((res) => {
    console.log(res)
    Promise.resolve().then(() => {
        console.log('promise3')
    })
})

equivalente a

new Promise((resolve) => {  
    console.log('promise2')
    resolve();
}).then(() => {
	Promise.resolve().then(() => {
        console.log('promise2.then')
    })
}).then(() => {
	Promise.resolve().then(() => {
        console.log('promise3')
    })
})

Los resultados son como sigue:

script start
a1 start
a2
promise2
script end
promise1
a1 end
promise2.then
promise3
setTimeout

Artículo de referencia

Publicados 134 artículos originales · ganado elogios 80 · Vistas a 30000 +

Supongo que te gusta

Origin blog.csdn.net/Umbrella_Um/article/details/100698686
Recomendado
Clasificación