Conocimiento profundo del mecanismo operativo de JavaScript

Conocimiento profundo del mecanismo operativo de JavaScript

Prefacio

  • Este artículo está escrito con motivo de la formación de los recién llegados al equipo, por lo que, de hecho, la audiencia de este artículo es un pequeño socio que no comprende el mecanismo operativo de JavaScript o tiene dificultades para entenderlo . En otras palabras, de hecho, los principios reales no son completamente consistentes con lo que describe este artículo. Al igual que los libros de texto de la escuela secundaria y los libros de texto de la universidad, los profesores universitarios te dirán que algunas cosas en la escuela secundaria son conclusiones obtenidas bajo ciertas circunstancias ideales, y este artículo es el mismo.
  • El propósito de este artículo es esperar que todos puedan tener una comprensión más intuitiva y rápida del mecanismo operativo de JavaScript después de leerlo, pero lo que es más importante, hágalo usted mismo , solo la práctica puede realmente descubrir problemas y mejorar :)
  • He recibido su apoyo y comentarios, muchas gracias :)

Para comprender el mecanismo operativo de JavaScript, debe comprender profundamente los siguientes puntos:

  • Mecanismo de hilo único de JavaScript
  • Cola de tareas (tareas sincrónicas y tareas asincrónicas)
  • Eventos y funciones de devolución de llamada
  • Temporizador
  • Bucle de eventos

Mecanismo de hilo único de JavaScript

Una de las características del lenguaje de JavaScript (y el núcleo del lenguaje) es de un solo subproceso . ¿Qué es un solo hilo? En pocas palabras, solo se puede hacer una cosa al mismo tiempo . Cuando hay varias tareas, solo se pueden completar una por una en un orden antes de ejecutar la siguiente.

El único hilo de JavaScript está relacionado con el uso de su lenguaje. Como lenguaje de programación del navegador, el objetivo principal de JavaScript es completar la interacción del usuario y manipular el DOM. Esto determina que solo puede ser de un solo subproceso, de lo contrario causará problemas de sincronización complicados.

Imagina que JavaScript tiene dos subprocesos al mismo tiempo. Un subproceso necesita agregar contenido a un determinado nodo DOM, y la operación del otro subproceso es eliminar este nodo. Entonces, ¿a quién debería tomar el navegador?

Entonces, para evitar la complejidad, JavaScript ha sido de un solo subproceso desde su inicio.

Para mejorar la utilización de la CPU, HTML5 propone el estándar Web Worker, que permite que los scripts JavaScript creen múltiples subprocesos, pero los subprocesos secundarios están completamente controlados por el subproceso principal y no deben manipular el DOM. Por lo tanto, este estándar no cambia la naturaleza de JavaScript de un solo subproceso.

Cola de tareas

Completar las tareas una por una significa que las tareas que se deben completar deben estar en cola, entonces, ¿por qué deben estar en cola?

Por lo general, hay dos razones para hacer cola:

  • El cálculo de la tarea es demasiado grande y la CPU está ocupada;
  • Las cosas necesarias para la tarea están listas y no pueden continuar ejecutándose, lo que hace que la CPU esté inactiva, esperando dispositivos de entrada y salida (dispositivos de E / S). > Por ejemplo, para algunas tareas, necesita Ajax para obtener datos antes de poder continuar

Como resultado, los diseñadores de JavaScript también se dieron cuenta de que en este momento, es posible ejecutar las tareas que están listas más tarde para mejorar la eficiencia operativa, es decir, suspender las tareas en espera y dejarlas a un lado, para luego ejecutarlas después de obtener las cosas que se necesitan. Es como cuando la otra persona se va al contestar la llamada y hay otra llamada entrante, por lo que cuelga la llamada actual, espera el final de la llamada y luego vuelve a conectarse a la llamada anterior.

Por tanto, han surgido los conceptos de sincronización y asincronía, y las tareas se dividen en dos tipos, una son tareas sincrónicas (Sincrónicas) y el otro son tareas asincrónicas (Asincrónicas).

  • Tareas síncronas: las tareas que deben ejecutarse se ponen en cola en el hilo principal, una tras otra, y la anterior se completa antes de que se ejecute la siguiente.
  • Tarea asincrónica: una tarea que no se ejecuta inmediatamente pero que debe ejecutarse se almacena en la "cola de tareas". La "cola de tareas" notificará al hilo principal cuándo y qué tarea asincrónica se puede ejecutar, y luego la tarea entrará en el hilo principal y Ser ejecutado. > Toda ejecución síncrona puede considerarse como ejecución asíncrona sin tareas asíncronas

En concreto, la ejecución asincrónica es la siguiente:

  • Todas las tareas de sincronización se realizan en el hilo principal para formar una pila de ejecución (pila de contexto de ejecución).

    Es decir, todas las tareas que se pueden ejecutar inmediatamente se ponen en cola en el hilo principal y se ejecutan una por una.

  • Además del hilo principal, también hay una "cola de tareas". Siempre que la tarea asincrónica tenga un resultado en ejecución, se coloca un evento en la "cola de tareas".

    Es decir, cuando cada tarea asincrónica está lista, se establece una bandera única, y esta bandera se usa para identificar la tarea asincrónica correspondiente.

  • Una vez que se ejecutan todas las tareas de sincronización en la "pila de ejecución", el sistema leerá la "cola de tareas" para ver qué eventos hay en ella. Aquellas tareas asincrónicas correspondientes terminan esperando el ensacado, ingresan a la pila de ejecución y comienzan a ejecutarse.

    Es decir, después de que el subproceso principal finaliza las tareas anteriores, buscará los indicadores en la "cola de tareas" para empaquetar las tareas asincrónicas correspondientes para su ejecución.

  • El hilo principal sigue repitiendo los tres pasos anteriores.

    Mientras el hilo principal esté vacío, leerá la "cola de tareas". Este proceso se repetirá continuamente, y así es como funciona JavaScript.

Eventos y funciones de devolución de llamada

evento

La "cola de tareas" es una cola de eventos (también se puede entender como una cola de mensajes). Cuando un dispositivo IO completa una tarea, agregará una hora a la "cola de tareas", lo que indica que la tarea asíncrona relacionada puede ingresar a la "pila de ejecución" . Luego, el hilo principal lee la "cola de tareas" para ver qué eventos hay en ella.

Además de los eventos del dispositivo IO, los eventos en la "cola de tareas" también incluyen algunos eventos generados por el usuario (como clics del mouse, desplazamiento de página, etc.). Siempre que se especifique la función de devolución de llamada, estos eventos entrarán en la "cola de tareas" y esperarán a que se lea el hilo principal.

Llamar de vuelta

La llamada "devolución de llamada" (callback) es el código que será suspendido por el hilo principal. Las tareas asincrónicas deben especificar una función de devolución de llamada.Cuando el subproceso principal comienza a ejecutar la tarea asincrónica, se ejecuta la función de devolución de llamada correspondiente.

La "cola de tareas" es una estructura de datos de primero en entrar, primero en salir, y el hilo principal lee primero los primeros eventos. El proceso de lectura del hilo principal es básicamente automático. Siempre que se borre la pila de ejecución, el primer evento en la "cola de tareas" entrará automáticamente en el hilo principal. Sin embargo, si se incluye un "temporizador", el hilo principal debe verificar primero el tiempo de ejecución, y ciertos eventos solo pueden regresar al hilo principal después del tiempo especificado.

Bucle de eventos

El hilo principal lee eventos de la "cola de tareas", este proceso es cíclico, por lo que todo el mecanismo operativo también se denomina "Bucle de eventos" (bucle de eventos)

Para comprender mejor Event Loop, consulte una imagen del discurso de Philip Roberts a continuación.

Bucle de eventos

En la figura anterior, cuando se está ejecutando el hilo principal, se generan el montón (montón) y la pila (pila). El código de la pila llama a varias API externas y agrega varios eventos (hacer clic, cargar, listo) a la "cola de tareas" . Cuando se ejecuta el código en la pila, el hilo principal leerá la "cola de tareas" y ejecutará las funciones de devolución de llamada correspondientes a esos eventos a su vez.

El código de la pila de ejecución (tarea síncrona) siempre se ejecuta antes de leer la "cola de tareas" (tarea asíncrona).

var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function (){};
req.onerror = function (){};
req.send();

El método req.send en el código anterior es una operación Ajax para enviar datos al servidor. Es una tarea asíncrona, lo que significa que el sistema leerá la "cola de tareas" solo después de que se ejecute todo el código del script actual. Por tanto, es equivalente a la siguiente escritura.

var req = new XMLHttpRequest();
req.open('GET', url);
req.send();
req.onload = function (){};
req.onerror = function (){};

En otras palabras, la parte de la función de devolución de llamada especificada (onload y onerror) es irrelevante antes o después del método send (), porque son parte de la pila de ejecución, y el sistema siempre leerá la "tarea" después de ejecutarlas. cola".

Temporizador

Además de colocar eventos para tareas asincrónicas, la "cola de tareas" también puede colocar eventos temporizados, es decir, especificar el tiempo después del cual se ejecutan ciertos códigos. Esto se denomina función de temporizador, que es el código que se ejecuta con regularidad.

SetTimeout()Y funciones que setInterval()se pueden utilizar para registrar llamadas únicas o repetidas después de un tiempo especificado, su mecanismo operativo interno es exactamente el mismo, la diferencia es que el código especificado por el primero se ejecuta una vez, y el segundo será llamado repetidamente a intervalos de un número especificado de milisegundos:

setInterval(updateClock, 60000); //60秒调用一次updateClock()

Debido a que son funciones globales importantes en JavaScript del lado del cliente, se definen como métodos del objeto Window.

Pero como función general, en realidad no le hace nada a la ventana.

Los setTImeout()métodos del objeto Window se utilizan para implementar una función que se ejecutará después de un número específico de milisegundos. Entonces acepta dos parámetros, el primero es la función de devolución de llamada y el segundo es el número de milisegundos para retrasar la ejecución. setTimeout()Y setInterval()devuelve un valor, que se puede pasar para clearTimeout()cancelar la ejecución de esta función.

console.log(1);
setTimeout(function(){console.log(2);}, 1000);
console.log(3);

El resultado de la ejecución del código anterior es 1, 3, 2, porque la ejecución de setTimeout()la segunda línea se pospone a 1000 milisegundos.

Si setTimeout()el segundo parámetro se establece en 0, significa que después de ejecutar el código actual (se borra la pila de ejecución), la función de devolución de llamada especificada se ejecutará inmediatamente (intervalo de 0 milisegundos).

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

El resultado de la ejecución del código anterior es siempre 2, 1, porque el sistema ejecutará la función de devolución de llamada en la "cola de tareas" solo después de que se ejecute la segunda línea.

En resumen, setTimeout(fn,o)el significado es especificar una tarea que se ejecutará en el tiempo libre disponible más temprano del hilo principal, es decir, que se ejecute lo antes posible. Agrega un evento al final de la "cola de tareas", por lo que no se ejecutará hasta que se procesen la tarea de sincronización y los eventos existentes de la "cola de tareas".

setTimeout()El valor mínimo (intervalo más corto) del segundo parámetro especificado por el estándar HTML5 no debe ser inferior a 4 milisegundos, si es inferior a este valor aumentará automáticamente.

Cabe señalar que setTimeout()solo el evento se inserta en la "cola de tareas" , y el hilo principal ejecutará su función de devolución de llamada designada solo después de que se ejecute el código actual (pila de ejecución). Si el código actual tarda mucho, es posible que deba esperar mucho tiempo, por lo que no hay forma de garantizar que la función de devolución de llamada se setTimeout()ejecute en el momento especificado.

Por razones históricas, el primer parámetro de setTimeout()suma setInterval()se puede pasar como una cadena. Si hace esto, la cadena se evaluará (equivalente a la ejecución eval()) después del período o intervalo de tiempo de espera especificado .

Para una comprensión profunda del principio de funcionamiento de los temporizadores, aquí hay un artículo de John Resig, autor de jQuery: http://ejohn.org/blog/how-javascript-timers-work/

También traduje este artículo yo mismo, si tiene alguna pregunta, corríjame: http://guoxunique.com/2016/12/07/how-javascript-timers-work/

Consulte la publicación del blog del profesor Ruanyifeng http://www.ruanyifeng.com/blog/2014/10/event-loop.html

Consulte la "Guía definitiva de JavaScript"

Supongo que te gusta

Origin blog.csdn.net/Amos_liu/article/details/53560434
Recomendado
Clasificación