Interpretación visual del bucle de eventos js y la diferencia entre el bucle de eventos del nodo y el bucle de eventos del navegador

experiencia técnica

El bucle de eventos de javaScript (Event Loop) es la base fundamental de su lenguaje de subproceso único que puede lograr una operación asíncrona eficiente. Si desea tener una comprensión más profunda de js, debe tener una comprensión clara del bucle de eventos. Después de la aparición de node, el entorno operativo de js ya no es un solo navegador. De manera similar, hay un bucle de eventos en node. Entonces, ¿qué es exactamente un bucle de eventos? Hay muchos artículos sobre bucles de eventos, pero parece un poco difícil de entender para algunos principiantes. Este artículo intenta tener una comprensión superficial o macro de los bucles de eventos, con la esperanza de expresar los bucles de eventos de forma más visual. Primero algunas preguntas de fondo.

Algunas preguntas de fondo:

1. ¿Qué es el hilo, el proceso, cuál es la diferencia y la conexión entre los dos?

Un proceso es la unidad más pequeña de asignación de recursos del sistema informático . La unidad más pequeña tiene memoria independiente entre sí, y un proceso tiene un espacio de memoria independiente;

Un subproceso es la unidad más pequeña de programación y asignación de la CPU de la computadora. La unidad de programación más pequeña es la unidad básica más pequeña que puede ejecutarse de forma independiente en la CPU. Un subproceso no tiene su propio espacio de memoria;

Un proceso puede tener muchos subprocesos, y cada subproceso realiza diferentes tareas en paralelo.

Comprensión visual:

Piense en las computadoras como una empresa

Un proceso es un departamento independiente, y cada departamento tiene sus propios recursos;

Un hilo es un empleado de cada departamento, cada empleado no tiene recursos y es la unidad de trabajo más pequeña, compartiendo recursos departamentales;

2. Por qué js es de un solo subproceso

Esto se relaciona principalmente con el uso de js. Antes de la aparición de node, js se usaba como lenguaje de scripting del navegador, principalmente para realizar la interacción entre el usuario y el navegador, y para operar el dom; esto determina que puede solo debe ser de un solo subproceso, de lo contrario traerá un problema de sincronización muy complicado.

Por ejemplo: si js está diseñado con subprocesos múltiples, si un subproceso quiere modificar un elemento dom y otro subproceso quiere eliminar el elemento dom, el navegador estará perdido y perdido...

Subproceso único y bucle de eventos (bucle de eventos)

JavaScript es de subproceso único y solo se puede ejecutar secuencialmente cuando se ejecuta código. Para resolver el bloqueo de la ejecución de código, js es asíncrono. Por ejemplo, cuando se encuentra con setTimeout, no se ejecutará después de que se ejecute el contenido del temporizador. Código, pero ejecute el código primero y luego ejecute el temporizador después de que se acabe el tiempo.

Basado en este mecanismo asincrónico, javaScript tiene su propio conjunto de reglas para ejecutar código para garantizar que el código se ejecute de manera eficiente y sin bloqueos.Esta regla es el bucle de eventos.

Tanto el nodo como el navegador proporcionan js con un entorno de ejecución, pero el mecanismo operativo de los dos es ligeramente diferente.

Mecanismo operativo del navegador js

Diferentes navegadores tienen diferentes motores js

Aunque los navegadores son diferentes, las reglas internas del ciclo de eventos son consistentes.

mecanismo operativo node.js

Node.js usa v8 como motor de análisis de js y usa libuv en el procesamiento de E/S.

La biblioteca libuv es responsable de la ejecución de la API del nodo y asigna diferentes tareas a diferentes subprocesos para formar un bucle de eventos. Devuelve el resultado de la ejecución al motor V8 de forma asíncrona.

Bucle de eventos en el navegador

Es más intensivo para el cerebro describir Event Loop directamente en palabras.Primero, introduzcamos los conceptos relacionados de Event Loop.

El bucle de eventos incluye la pila de ejecución , la cola de eventos, la microtarea, la macrotarea, la pila de ejecución y la cola de eventos son direcciones para almacenar eventos en el bucle de eventos, y las microtareas y macrotareas son eventos que se ejecutan en el bucle de eventos.

Pila de ejecución:

Después de cargar el código general de js, comenzará a ejecutarse. En este momento, se generará un contexto de ejecución (contexto). Después de ejecutar el código, se liberará el contexto de ejecución. Para un contexto de ejecución, también se puede llamar el entorno de ejecución js actual , incluido el ámbito privado, las variables en el ámbito actual, el ámbito superior y el objeto de ámbito actual this .

Dado que js es de un solo subproceso, cuando se ejecuta el código anterior, el código siguiente está esperando a ser ejecutado.En este momento, esta parte del código (función o código directamente ejecutable) se coloca en una pila, llamada pila de ejecución .

Cola de eventos:

La operación js anterior solo considera eventos síncronos. Cuando se encuentran eventos asíncronos (o eventos de temporización) durante la ejecución de js , los eventos correspondientes se suspenderán y js agregará este evento a otra cola diferente de la pila de ejecución actual. Continúe ejecutando el código síncrono en el contexto de ejecución actual.Esta cola que almacena eventos asíncronos se denomina cola de eventos.

Después de borrar la pila de ejecución en un entorno de ejecución, js verificará si la cola de eventos está vacía en este momento y, si no lo está, continuará ejecutando estos eventos.

Al ejecutar los eventos en la cola de eventos, seguirá las reglas de la pila de ejecución. Primero, se generará un contexto de ejecución correspondiente al evento actual, y luego se generará la pila de ejecución y la cola de eventos. Cuando el código en la se ejecuta el entorno de ejecución y se devuelve el resultado, js saldrá del entorno de ejecución y destruirá el entorno de ejecución, y volverá al entorno de ejecución del método anterior. Luego ejecute el siguiente evento en la cola de eventos, las mismas reglas. Cuando se vacía la cola de eventos, el entorno de ejecución externo se destruye y la ejecución finaliza.

Se puede ver en el análisis anterior que el bucle de eventos se refiere a la ejecución de código en la cola de eventos que repite las reglas de la pila de ejecución externa y profundiza capa por capa para formar un ciclo.

Dos puntos de atención:

1. Las tareas síncronas tienen prioridad sobre las tareas asíncronas en el mismo contexto de ejecución

2. El orden de ejecución de tareas asincrónicas en diferentes entornos de ejecución depende del orden en que se agregan a la cola de eventos

3. La cola de eventos es la misma en diferentes entornos de ejecución

ejemplo:

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


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


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

a()
b()

// 运行结果
// a
// b

// 上层
// a1
// b1

cambio de hora

function a(){
    console.log('a')
    setTimeout( () => {
        console.log('a1')
    },100)
}


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


setTimeout( () => {
    console.log('上层')
},10)

a()
b()

// 运行结果
// a
// b
// b1
// 上层
// a1

Comprensión visual del bucle de eventos:

Piense en el método en el código js como un paciente en el hospital ,

La pila de ejecución son todos los pacientes, en orden

Las tareas síncronas son visitas directas al paciente

La tarea asincrónica es el paciente que necesita hacerse la prueba y ver a un médico después de obtener el resultado.

en bucle

Si los pacientes que necesitan hacerse la prueba pertenecen a un grupo, los pacientes que esperan en la cola en la parte de atrás pasarán al siguiente grupo después de que todos los pacientes que están viendo directamente al médico de este grupo hayan terminado de leer.

 

Microtareas:

  • new Promise()
  • new MutaionObserver()

Tarea de macros:

  • setInterval()
  • setTimeout()
  • código general
  • Operaciones de E/S, representación de interfaz de usuario

En un bucle de eventos, los eventos asincrónicos devuelven resultados y se colocan en una cola de tareas. Sin embargo, según el tipo de evento asíncrono, el evento se pondrá en cola en la cola de macrotarea o microtarea correspondiente. Y cuando la pila de ejecución actual esté vacía, el subproceso principal verificará si hay eventos en la cola de microtareas. Si no existe, vaya a la cola de tareas de la macro para sacar un evento y agregue el retorno correspondiente a la pila de ejecución actual; si existe, la devolución de llamada correspondiente al evento en la cola se ejecutará a su vez hasta que la micro la cola de tareas está vacía, y luego vaya a la tarea macro Saque el primer evento de la cola y agregue la devolución de llamada correspondiente a la pila de ejecución actual... y así sucesivamente, e ingrese al bucle.

Resumen: La cola de eventos se divide en cola de microtareas y cola de macrotareas.En el mismo ciclo de eventos, las microtareas siempre se ejecutan antes que las macrotareas.

Comprensión visual:

Las microtareas son pacientes de emergencia que necesitan pruebas.

La tarea macro es un paciente común que necesita ser probado

Bucle de eventos en el nodo

Del mecanismo operativo del nodo, sabemos que la biblioteca ibuv es responsable de la ejecución de la API del nodo.

El significado de cada etapa:

  • temporizadores: esta etapa ejecuta las devoluciones de llamada en la cola del temporizador, como  setTimeout() y  setInterval().
  • Devoluciones de llamada de E/S: esta fase ejecuta casi todas las devoluciones de llamada. Pero no incluye evento de cierre, temporizador y setImmediate()devolución de llamada.
  • inactivo, preparar: esta fase solo se usa internamente y se puede ignorar.
  • sondeo: en espera de nuevos eventos de E/S, el nodo se bloqueará aquí en algunos casos especiales.
  • La devolución de llamada de check:  setImmediate()se ejecutará en esta etapa.
  • cerrar devoluciones de llamada: por ejemplo, socket.on('close', ...)la devolución de llamada de este evento de cierre.

orden de ejecución

Cuando un motor v8 analiza el código js y lo transfiere al motor libuv, el bucle primero ingresa a la fase de encuesta.La fase de encuesta es equivalente al análisis del código de sincronización general, se generará una pila de ejecución y la cola de encuesta se borrará al mismo tiempo, y luego irá setImmediate的回调放入check队列,在setTimeout() a  setInterval()定时到期后把其回调事件放入timers队列,la etapa de verificación, verificará y ejecutará la cola de verificación, verificará y ejecutará la cola del temporizador y luego ingresará a la etapa de devolución de llamada para ejecutar la devolución de llamada. El orden de verificación y temporizador no es fijo y se ve afectado por el entorno en el que se ejecuta el código.

Después de ingresar a una nueva etapa, las etapas anteriores se repetirán hasta que se complete la ejecución y se ingrese a la siguiente etapa.

总结:

poll polling pertenece al observador io, process.nextTick() pertenece al observador inactivo y setImmediate() pertenece al observador de verificación.

En cada ronda de verificación de bucle, los observadores inactivos preceden a los observadores de E/S y los observadores de E/S preceden a los observadores de verificación.

Al ingresar el código por primera vez, el observador inactivo no existe.

proceso.nextTick() en el nodo

process.nextTick() es una cola especial en el nodo. Estos eventos se ejecutarán primero cuando cada etapa se complete y esté lista para ingresar a la siguiente etapa. Es decir, se ejecuta process.nextTick() cuando se cambia de etapa. Y, sin importar cuán profunda sea la devolución de llamada, se ejecutará una vez.

Promesa

La etapa anterior no incluye Promise. En el nodo, la promesa es similar al navegador. Se ejecuta después de process.nextTick() y antes de setTimeout

Ejemplo:

const fs = require('fs')
const path = require('path')

const wait = () => new Promise((resolove, reject) => {
  setTimeout(resolove(true), 3)
})
fs.readFile(path.resolve(__dirname, './vue.config.js'), 'utf-8', async (err, data) => {
  console.log('读取的文件内容')
  await wait()
  console.log('测试测试')
  process.nextTick(() => {
    console.log('nextTick')
  })
})

setTimeout(() => {
  console.log('定时器任务0')
}, 0)


setTimeout(() => {
  console.log('定时器任务100')
}, 1000)


setImmediate(() => {
  console.log('立即执行')
})

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

process.nextTick(() => {
  console.log('外层nextTick')
})

console.log('外层同步')
// 运行结果
// 外层同步
// 外层nextTick
// promise
// 定时器任务0
// 立即执行
// 读取的文件内容
// 测试测试
// nextTick
// 定时器任务100

Comprensión visual

Explorador terco (ve hasta el final de cada habitación)

Todos los códigos son como laberintos que se han creado, y el motor es la persona que va a explorar, lo llamamos Xiaodai.

Xiaodai llegó al laberinto y ya tenía un mapa, por lo que se arriesgó de acuerdo con el mapa.

El laberinto tiene seis salas, a saber, temporizador, i/o callback, ide prepare (uso interno, cerrado) , poll, check, close callback,

Entre ellos, el temporizador es una sala de realidad virtual y Xiaodai puede ver la escena en el interior en cualquier momento.

Cada una de las otras habitaciones tiene cinco habitaciones, algunas están abiertas y otras no.

Reglas de expedición: cada vez que salga de una habitación, compruebe si hay heridos ( peocess.nextTick() )

Xiaodai primero ingresa a la sala de votación, comienza a explorar (ejecuta la cola de la encuesta), luego ingresa a la sala de verificación, la sala del temporizador (aleatoria), sale después de la exploración, ingresa a la devolución de llamada cerrada, ingresa a la sala de devolución de llamada/io después de la exploración, y finalmente completa la exploración y se va.

Xiaodai dijo que la tarea finalmente se completó.

referencia:

https://zhuanlan.zhihu.com/p/33058983

https://zhuanlan.zhihu.com/p/54882306

 

 

 

Supongo que te gusta

Origin blog.csdn.net/qdmoment/article/details/105804253
Recomendado
Clasificación