Cola de mensajes del navegador y mecanismo de bucle de eventos (macrotask y microtask)

introducción

En la era actual de Internet, utilizamos a menudo navegadores para acceder a diversas páginas web y aplicaciones. Sin embargo, ¿alguna vez has pensado en cómo el navegador maneja y ejecuta los diversos eventos y tareas que activamos en la página web? Esto involucra la cola de mensajes y el mecanismo de bucle de eventos del navegador.

Como sistema de software complejo, un navegador necesita administrar y realizar de manera eficiente diversas tareas para garantizar que los usuarios puedan utilizar páginas web y aplicaciones sin problemas. La cola de mensajes y el mecanismo de bucle de eventos son los mecanismos principales utilizados por los navegadores para manejar estas tareas.

En este artículo, profundizaremos en la cola de mensajes y los mecanismos de bucle de eventos del navegador, y aprenderemos sobre los conceptos de macrotareas y microtareas. Aprenderemos más sobre cómo las colas de mensajes organizan y programan tareas, y cómo los bucles de eventos coordinan el orden de ejecución de las tareas. Si comprendemos en profundidad estos mecanismos, podremos optimizar mejor nuestras páginas web y aplicaciones para mejorar la experiencia del usuario. ¡Ahora comencemos a explorar la cola de mensajes y el mecanismo de bucle de eventos del navegador!

Antes de comenzar el texto, pensemos en una pregunta.
问题:js是单线程的,那它是如何同时处理多个任务的呢?
Aunque JavaScript tiene un solo subproceso, la razón por la que puede manejar múltiples tareas al mismo tiempo es porque utiliza un modelo de programación asincrónico. La programación asincrónica permite que JavaScript continúe realizando otras tareas sin bloquear la ejecución del programa hasta que se complete la tarea. Cuando se encuentra con operaciones que consumen mucho tiempo (como solicitudes de red o lectura y escritura de archivos), JavaScript delegará estas tareas a otros subprocesos del navegador, de modo que el subproceso principal pueda continuar realizando otras tareas.

JavaScript utiliza mecanismos como funciones de devolución de llamada, detectores de eventos y promesas (Promise) para manejar tareas asincrónicas. Cuando se completa una tarea asincrónica, activa una función o evento de devolución de llamada, o devuelve un objeto de promesa para que el código pueda continuar ejecutándose una vez completada la tarea.

Por ejemplo, cuando se realiza una solicitud de red, JavaScript envía la solicitud al hilo de red del navegador y continúa ejecutando el código detrás de ella. Cuando se completa la solicitud de red, el navegador devuelve el resultado a JavaScript y notifica el código a través de una función o evento de devolución de llamada. Este mecanismo de procesamiento asincrónico permite que JavaScript continúe procesando otras tareas mientras espera solicitudes de red, lo que mejora el rendimiento del programa y la experiencia del usuario.

Aunque JavaScript tiene un solo subproceso, puede manejar múltiples tareas simultáneamente a través de un modelo de programación asincrónico, lo que le brinda la capacidad de procesar múltiples tareas .

1. La cola de mensajes y el mecanismo de bucle de eventos del navegador.

1. Información general

El mecanismo de cola de mensajes y bucle de eventos en el navegador es una forma de manejar tareas asincrónicas. Los navegadores deben poder manejar múltiples tareas al mismo tiempo, como solicitudes de red, interacciones de usuarios, etc. Para evitar el bloqueo de tareas, los navegadores utilizan colas de mensajes para administrar el orden de ejecución de las tareas y procesar la ejecución de las tareas a través del mecanismo de bucle de eventos.

浏览器
渲染引擎
JS引擎
消息队列
事件循环
执行上下文

El principio de funcionamiento se muestra en la siguiente figura:

JS Runtime
Browser
Call Stack
JS Engine
Callback Queue
Web APIs
Render Engine
Main Thread
Layout
Painting
Event Loop
待处理任务队列
处理任务

2. Cola de mensajes

Cola de mensajes: el navegador proporciona una cola de mensajes (también conocida como cola de tareas) para almacenar tareas pendientes. Cuando se completa una tarea asincrónica, se agrega a una cola de mensajes para su ejecución.

La cola de mensajes de un navegador es un mecanismo para gestionar eventos pendientes. Su función es agregar varios eventos desencadenantes (como interacción del usuario, solicitud de red, temporizador, etc.) a la cola y luego ejecutarlos secuencialmente en el orden de primero en entrar, primero en salir.

El proceso específico es el siguiente:

  1. Cuando ocurre un evento en el navegador, como cuando el usuario hace clic en un botón, el navegador agregará el evento a la cola de mensajes.
  2. La cola de mensajes ordena los eventos y los procesa en el orden en que se agregaron.
  3. El bucle de eventos toma eventos de la cola de mensajes y los envía al contexto de ejecución para su procesamiento.
  4. El contexto de ejecución realiza las operaciones correspondientes según el tipo de evento y la función de devolución de llamada registrada.
  5. El bucle de eventos continúa recuperando el siguiente evento de la cola de mensajes y repite el proceso anterior hasta que la cola de mensajes esté vacía.

A través de la cola de mensajes, el navegador puede garantizar la secuencia y las capacidades de procesamiento asincrónico de los eventos. Este mecanismo garantiza que las tareas de larga duración no bloqueen la capacidad de respuesta de la interfaz de usuario y proporciona una experiencia de usuario más fluida.

3. Bucle de eventos

El bucle de eventos se refiere al proceso en el que el navegador busca continuamente tareas de la cola de mensajes y las ejecuta . El navegador comprobará continuamente la cola de mensajes en busca de tareas de forma cíclica. Cuando la cola de mensajes no está vacía, el navegador sacará la primera tarea de la cola y la ejecutará hasta que la cola esté vacía. Si la cola de mensajes está vacía, el navegador entrará en modo de suspensión y esperará a que se unan nuevas tareas.

El mecanismo de bucle de eventos del navegador es responsable de sacar tareas de la cola de mensajes y entregarlas al motor JavaScript para su ejecución. Cada proceso de ejecución de bucle de eventos se denomina marco de evento.

El flujo básico del bucle de eventos es el siguiente:

  1. Obtenga una tarea de la cola de mensajes.
  2. 根据任务的类型,将其交给相应的处理机制处理。例如,如果是用户交互产生的事件,会触发相应的事件处理函数。
  3. 处理完一个任务后,判断是否需要更新页面渲染。
  4. 如果需要更新渲染,则执行渲染操作。
  5. 重复以上步骤,进行下一个事件帧的循环。

举例说明:

假设有以下代码:

console.log('1');

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

console.log('3');

执行过程如下:

  1. 打印 “1”。
  2. 遇到 setTimeout,将回调函数放入消息队列中,并设置延时为0。
  3. 打印 “3”。
  4. 事件循环开始,从消息队列中取出第一个任务(即 setTimeout 的回调函数),并执行。
  5. 打印 “2”。

通过上述示例可以看出,即使 setTimeout 的延时设为0,仍然会在打印 “3” 之后才执行回调函数。这是因为在执行过程中,浏览器首先会执行同步任务(如打印 “1” 和 “3”),然后再从消息队列中取出下一个任务执行。

总结:
消息队列和事件循环机制使得浏览器能够在处理异步任务时实现非阻塞的方式。事件循环不断地从消息队列中取出任务并执行,从而保证了任务的按序执行。

二、浏览器中的宏任务(Macro task)和微任务(Micro task)

浏览器在解析JavaScript代码时,使用宏任务和微任务队列是为了能够正确地处理异步操作和优化任务执行顺序。

事件循环中,任务可以被分为宏任务微任务两种类型:

  • 宏任务macro task):包括但不限于 setTimeout、setInterval、I/O 操作等。
  • 微任务micro task):包括 Promise 的回调函数、MutationObserver的回调函数等。

通过将异步操作区分为宏任务和微任务,浏览器可以更好地管理事件循环。事件循环是浏览器运行JavaScript的机制,在事件循环中,浏览器会从宏任务队列中取出一个任务执行,然后执行微任务队列中的所有任务,直到微任务队列为空。然后再取出一个宏任务执行,依此往复

这种机制可以保证异步操作按照正确的顺序执行,并能够优先处理微任务,这有助于提高页面的响应性能和用户体验。同时,由于微任务执行时机早,可以在下一个宏任务之前进行一些重要的操作,比如对DOM进行修改,这样可以避免一些不必要的重绘和回流操作,提升性能。

这种机制保证了微任务的优先级高于宏任务,因此微任务的执行顺序会优先于宏任务

总之,宏任务和微任务队列的设计是为了保证异步操作的顺序和性能,提供更好的用户体验

2023-09-01 2023-09-01 2023-09-02 2023-09-02 2023-09-03 2023-09-03 2023-09-04 2023-09-04 2023-09-05 2023-09-05 2023-09-06 2023-09-06 2023-09-07 Fetch Macrotask Script Microtask Layout Paint Macrotask Composite Macrotask Macrotask Message Queue Event Loop

上图展示了浏览器在解析JavaScript时的消息队列和事件循环机制,同时显示了事件循环中的宏任务和微任务。以下是解释:

  • 当浏览器解析网页时,首先执行宏任务Fetch,通常是从服务器获取所需资源。这个过程可能需要花费几天的时间。

  • 接着是宏任务Script,这是执行 JavaScript 代码的阶段,通常只需要几毫秒或几秒的时间。

  • Script任务期间,如果有微任务(例如 Promise 的回调函数、MutationObserver 等)被注册,它们将被添加到微任务队列中。

  • Script任务执行完毕后,事件循环将检查微任务队列是否为空。如果不为空,将按照先进先出(FIFO)的顺序立即执行所有微任务。

  • 宏任务Layout表示对 DOM 进行重新布局,通常包括计算元素在页面中的位置、尺寸等。这个过程可能需要几天的时间。

  • 宏任务Paint标识绘制页面元素颜色和样式,通常包括页面渲染、绘制元素等。这个过程可能需要几天的时间。

  • 最后,宏任务Composite表示将已渲染的页面元素组合成最终的可见图像。这个过程可能需要一天的时间。

这样,整个事件循环过程就完成了一次循环。需要注意的是,宏任务可以有多个,它们按照顺序执行,但是微任务将在每个宏任务完成后立即执行,不会被插入宏任务之间。

浏览器的宏任务和微任务执行机制如下:

Script task
Macro task
Micro task
Macro task queue
Micro task queue
Execution context

解释如下:

  1. 浏览器中的任务分为宏任务和微任务两种类型。

  2. 宏任务(Macro task)通常包括整体代码script、setTimeout、setInterval、I/O、UI渲染等,它们按照顺序依次执行。

  3. 微任务(Micro task)主要包括Promise、MutationObserver等,它们的执行在宏任务之间执行。

  4. 当执行顺序到达宏任务时,它们会被放入宏任务队列(Macro task queue)中等待执行。

  5. 当执行顺序到达微任务时,它们会被放入微任务队列(Micro task queue)中等待执行。

  6. 在执行宏任务前,先执行完微任务队列中的所有微任务。当一个宏任务执行完后,会查看微任务队列中是否存在微任务,如果有,则继续执行微任务。

举个例子来说明:

console.log('1');

setTimeout(function() {
    
    
    console.log('2');
    Promise.resolve().then(function() {
    
    
        console.log('3');
    });
});

Promise.resolve().then(function() {
    
    
    console.log('4');
});

console.log('5');

在这个例子中,首先会输出’1’,因为它是在第一个宏任务中直接执行的。然后,遇到了一个 setTimeout,它是一个宏任务,所以会被加入到宏任务队列,并继续执行后面的语句,输出’5’。当第一个宏任务执行完毕后,会从宏任务队列中取出下一个宏任务,这时候会先执行微任务队列中的任务,输出’4’。紧接着,会执行 setTimeout 的回调函数,输出’2’,并且立即创建一个微任务并加入微任务队列,输出’3’。最后,宏任务队列中没有任务了,完成整个事件循环的执行过程。

因此,上述代码的输出结果为:

1
5
4
2
3

综上所述,该示例中的宏任务和微任务依次按照顺序执行,保持了JavaScript的单线程特性。

总结

总结起来,浏览器的消息队列和事件循环机制是保证 JavaScript 代码执行顺序的关键。在浏览器中执行的代码分为宏任务和微任务,宏任务包括整体的script代码、setTimeoutsetInterval 等,而微任务则包括 Promise、MutationObserver 等。

事件循环机制的原理是不断从宏任务队列中取出一个任务执行,然后检查微任务队列是否有任务需要执行,如果有,则一直执行微任务队列中的任务,直到微任务队列为空。这样的机制保证了 JavaScript 代码能够按照预期的顺序执行,同时还能处理异步任务和事件回调。

了解浏览器的消息队列和事件循环机制对于开发者来说是非常重要的,它有助于我们优化代码和处理异步操作,避免意外的行为和错误。在编写 JavaScript 代码时,我们应该合理地使用宏任务和微任务,避免堵塞主线程,提高页面的渲染性能和响应能力。

希望通过这篇介绍,读者们能够更好地理解浏览器的消息队列和事件循环机制,能够更加灵活地编写 JavaScript 代码,提高开发效率和用户体验。

Supongo que te gusta

Origin blog.csdn.net/jieyucx/article/details/132623822
Recomendado
Clasificación