English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Este artículo introduce el mecanismo de temporización de JavaScript, para entender el mecanismo de temporización de JavaScript, es necesario saber el mecanismo de ejecución de JavaScript.
Primero de todo, declare que JavaScript se ejecuta en un solo hilo (hilo del motor JavaScript) y es impulsado por eventos.
I. Hay varios hilos en el navegador
El navegador más básico que contiene un hilo:
1、Hilo del motor JavaScript.
2、Hilo de temporizador, setInterval y setTimeout disparan este hilo.
3、Hilo de disparo de eventos del navegador, este hilo dispara eventos como onclick, onmousemove y otros eventos del navegador.
4、Hilo de renderizado de interfaz, responsable de renderizar los elementos HTML de la interfaz del navegador. Nota: durante la ejecución del script por el motor JavaScript, el hilo de renderizado de interfaz está en estado de suspensión. Es decir, cuando se utilizan JavaScript para operar en los nodos de la interfaz, no se manifiestan inmediatamente, sino que esperan a que el hilo del motor JavaScript esté libre para manifestarse. (Esto se dice al final)
5、Hilo de solicitud HTTP (las solicitudes Ajax también están incluidas).
Estos hilos, bajo el control del núcleo del navegador del navegador, se coordinan entre sí para completar el trabajo (no lo sé exactamente).
II. Cola de tareas
Sabemos que JavaScript es un hilo único, todo el código JavaScript se ejecuta en el hilo del motor JavaScript. En los artículos del profesor Ruan Yifeng, este hilo se llama hilo principal, que es una pila de ejecución. (El siguiente contenido también se resume principalmente según la comprensión y resumen del artículo del profesor Ruan Yifeng.)
Estos códigos JavaScript podemos considerarlos como una serie de tareas, estas tareas tienen tareas sincrónicas y tareas asíncronas. Las tareas sincrónicas (como sentencias de asignación de variables, sentencias alert, sentencias de declaración de funciones, etc.) se ejecutan directamente en la línea principal en orden, y las tareas asíncronas (como eventos de disparo de hilos de eventos del navegador, respuestas del servidor devueltas por Ajax, etc.) se colocan en cola en el cola de tareas (también puede llamarse cola de eventos, cola de mensajes) según el orden de tiempo, esperando ser ejecutadas. Tan pronto como se completan las tareas en la línea principal, se verifica la cola de tareas para ver si hay tareas esperando en cola, y si las hay, se permite que las tareas en cola entren en la línea principal para ejecutarse.
Por ejemplo, el siguiente ejemplo:}
!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Mejora de programación</title> <style type="text/css"> body{ margen: 0; rejilla: 0; posición: relativa; alto: 600px; } #test{ alto: 30px; ancho: 30px; posición: absoluta; izquierda: 0; top: 100px; fondo-color: rosa; } </style> </head> <body> <div id="test"> </div> <script> var pro = document.getElementById('test'); pro.onclick = function() { alert('No se ejecutó inmediatamente.'); }; function test() { a = new Date(); var b=0; for(var i=0;i<3000000000;i++) { b++; } c = new Date(); console.log(c-a); } test(); </script> </body> </html>
En este ejemplo, la función test() se ejecuta aproximadamente,8~9Después de unos segundos, por lo que cuando abrimos esta página, en,8Clics antes de unos segundos en el cuadrado rosa, no aparecerá inmediatamente el cuadro de mensaje emergente, sino que tendrá que esperar hasta,8Después de unos segundos, aparecerá y además,8Clics antes de unos segundos en el cuadro rosa,8Después de unos segundos, aparecerán varias veces.
Cuando abrimos esta página, el hilo principal primero declara la función test, luego declara la variable pro, luego asigna el nodo p al pro, luego agrega el evento click al nodo p y especifica la función de retroalimentación (en espera), luego llama a la función test y ejecuta el código dentro de ella. Durante la ejecución del código dentro de la función test, hacemos clic en el nodo p, el hilo de eventos del navegador detecta este evento y lo coloca en la cola de tareas, de modo que cuando el hilo principal complete las tareas en la cola (aquí la función test), al verificar la cola de tareas, encuentra este evento y ejecuta la función de retroalimentación correspondiente. Si hacemos clic varias veces, estos eventos desencadenados múltiples se pondrán en cola en el orden de su tiempo de desencadenamiento (se puede agregar otro elemento con un evento de clic y alternar entre diferentes elementos para verificar).
A continuación, se resume el mecanismo de ejecución de las tareas:
El mecanismo de ejecución asíncrona es el siguiente. (La ejecución sincrónica también es así, ya que se puede considerar como una ejecución asíncrona sin tareas asíncronas.).
1Todas las tareas sincrónicas se ejecutan en el hilo principal, formando una pila de contexto de ejecución (execution context stack).
2Además del hilo principal, existe una "cola de tareas" (task queue). Tan pronto como una tarea asíncrona tiene un resultado, se coloca un evento en la "cola de tareas".
3Una vez que todas las tareas sincrónicas se hayan ejecutado en la "pila de ejecución" (stack), el sistema leerá la "cola de tareas" para ver qué eventos hay dentro. Las tareas asíncronas correspondientes, por lo tanto, salen de su estado de espera y entran en la pila de ejecución para comenzar a ejecutarse.
4El hilo principal repite el tercer paso continuamente.
Tres, eventos y funciones de retroalimentación
Cuando especificamos eventos para elementos DOM, siempre especificamos una función de retroalimentación para que se ejecute el código correspondiente cuando realmente ocurra el evento.
La función de retroalimentación del evento en el hilo principal se pondrá en espera, si hay eventos correspondientes en cola de tareas, cuando el hilo principal los detecte, se ejecutará la función de retroalimentación correspondiente. También podemos decir que el hilo principal ejecuta tareas asíncronas, es decir, ejecuta las funciones de retroalimentación correspondientes.
Cuatro, bucle de eventos
El proceso de verificación del hilo principal en la cola de eventos es continuo en bucle, por lo que podemos dibujar un diagrama de bucle de eventos:
En la imagen superior, la línea principal produce la pila y ejecuta la pila, después de que se completan las tareas en la pila, la línea principal verifica los eventos que se han producido y se han introducido en la cola de tareas por otros hilos, detecta el evento que está en la parte superior de la cola, encuentra la función de devolución de llamada correspondiente del callback suspendido, luego la ejecuta en la pila de ejecución, y este proceso se repite una y otra vez.
Cinco, temporizadores
Combinando estos conocimientos, hablemos de los temporizadores en JavaScript: setTimeout() y setInterval().
setTimeout(func, t) es una llamada de tiempo de espera, que llama a la función después de un tiempo determinado. Este proceso en el ciclo de eventos es el siguiente (mi comprensión):
Después de que la línea principal ejecute la sentencia setTimeout(func, t);, coloca la función de devolución de llamada func en espera, y el hilo de temporizador comienza a contar el tiempo. Cuando el tiempo contado es igual a t, es equivalente a que se ha producido un evento, que se introduce en la cola de tareas (termina el conteo, solo se cuenta una vez), cuando la línea principal completa la ejecución de las tareas, la línea principal verifica la cola de tareas y encuentra este evento, luego ejecuta la función de devolución de llamada suspendida func. El intervalo de tiempo especificado t es solo un valor de referencia, la verdadera duración del intervalo depende del tiempo que tarde el código en ejecutarse después de ejecutar la sentencia setTimeout(func, t);, y es solo mayor o igual. (Incluso si establecemos t en 0, también se debe pasar por este proceso).
setInterval(func, t) es una llamada intermitente, que llama a la función a intervalos regulares. Este proceso en el ciclo de eventos es similar al anterior, pero también diferente.
setTimeout() es agregar un evento a la cola de tareas del hilo de temporizador después de un tiempo t (nota: es un evento), mientras que setInterval() es agregar un evento a la cola de tareas del hilo de temporizador después de cada tiempo t (siempre está contando, a menos que se elimine la llamada intermitente), independientemente de si el evento agregado anteriormente ha sido detectado y ejecutado por la línea principal. (En realidad, el navegador es bastante inteligente, si el navegador detecta que ya hay en la cola de tareas un evento de llamada intermitente de setInterval con el mismo ID, simplemente mata el nuevo evento. Es decir, en la cola de tareas solo puede existir un evento de llamada intermitente de un mismo ID.).
Por ejemplo, si el código después de ejecutar setInterval(func, t); toma2El tiempo de t, cuando2Después de t tiempo, la línea principal detecta el primer evento de llamada intermitente introducido por el hilo de temporizador en la cola de tareas, y la función func comienza a ejecutarse. Después de que la primera función func se ejecute por primera vez, el segundo evento de llamada intermitente ya ha entrado en la cola de tareas, y la línea principal detecta inmediatamente el segundo evento de llamada intermitente, y la función func se ejecuta de inmediato. En este caso, las dos ejecuciones de la función func son sucesivas, sin intervalo de tiempo entre ellas.
Aquí hay un ejemplo:
function test() { a = new Date(); var b=0; for(var i=0;i<3000000000;i++) { b++; } c = new Date(); console.log(c-a); } function test2() { var d = new Date().valueOf(); //var e = d-a; console.log('El momento en que fui llamado es:'+d+'ms'); //alert(1); } setInterval(test2,3000); test();
Resultados:
Por qué8.6no hubo dos momentos iguales, la razón se puede encontrar en el contenido anterior.
pasaron unos segundos después de que el bucle for del ejemplo se ejecutó8601ms, durante la ejecución del bucle for, solo hay un evento de llamada intermitente en cola (razones como se mencionó anteriormente), cuando8601ms después de que el primer evento de llamada intermitente entra en la pila de ejecución del hilo principal, para este ejemplo, en este momento la cola de tareas está vacía, por lo que se puede introducir otro evento de llamada intermitente, por lo que1477462632228ms en este momento el segundo evento de llamada intermitente (de hecho debería ser el tercero) se introduce en la cola de tareas, ya que la pila de ejecución del hilo principal está vacía, por lo que el hilo principal toma inmediatamente el callback correspondiente para ejecutarlo, la diferencia entre la segunda y la primera llamada es320ms (de hecho8601+320=8920, más o menos, es igual a9Después de unos segundos, vemos que la tercera llamada se恢复正常,ya que en este momento no hay otro código en la hilo principal, solo una tarea, es ejecutar la función de callback de la llamada intermitente en intervalos regulares.
Ejemplo de llamada intermitente implementada con setTimeout():
function test() { a = new Date(); var b=0; for(var i=0;i<3000000000;i++) { b++; } c = new Date(); console.log(c-a); } function test2(){ var d = new Date().valueOf(); console.log('El momento en que fui llamado es:'+d+'ms'); setTimeout(test2,3000); } setTimeout(test2,3000); test();
Resultados:
El intervalo de tiempo entre dos llamadas es básicamente el mismo. ¿Por qué piensa que es así?
Vea otro ejemplo:
!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Flex布局练习</title> <style type="text/css"> body{ margen: 0; rejilla: 0; posición: relativa; alto: 600px; } #test{ alto: 30px; ancho: 30px; posición: absoluta; izquierda: 0; top: 100px; fondo-color: rosa; } </style> </head> <body> <div id="test"> </div> <script> var p = document.createElement('p'); p.style.width = '';50px'; p.style.height = '';50px'; p.style.border = '';1px solido negro'; document.body.appendChild(p); alert('ok'); </script> </body> </html>
El resultado de este ejemplo es que primero se abre el cuadro de diálogo de advertencia y luego aparece el elemento p con borde negro en la página. La razón es很简单, solo una frase:
Durante el tiempo de ejecución del script en el motor JavaScript, la línea de renderizado de la interfaz se encuentra en estado de espera. Es decir, cuando se realiza una operación en los nodos de la interfaz utilizando JavaScript, no se manifestará inmediatamente. Solo se manifestará cuando la línea de hilo de JavaScript esté libre.
Esta es mi comprensión y resumen del mecanismo de temporización de JavaScript en JavaScript. Si hay errores, espero que los grandes maestros me corrijan. También espero que todos apoyen y griten lecciones.
Declaración: el contenido de este artículo se obtiene de la red, y el derecho de autor pertenece al propietario original. El contenido es contribuido y subido por los usuarios de Internet de manera autónoma. Este sitio no posee los derechos de propiedad, no ha sido editado por humanos y no asume responsabilidad alguna por él. Si encuentra contenido sospechoso de copyright, le invitamos a enviar un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar y proporcionar evidencia relevante. Una vez verificada, este sitio eliminará de inmediato el contenido sospechoso de infracción.