medium - JavaScript: ¿Cuándo exactamente la pila de llamadas se “vacía”?
event loop y asincronía (4)
He leído varias publicaciones / subprocesos SO en el bucle de eventos, y de acuerdo con el artículo de MDN ,
Cuando la pila está vacía, se saca un mensaje de la cola y se procesa.
Como un novato en JS, lo que aún me confunde es: ¿cuándo exactamente la pila de llamadas se "vacía"? Por ejemplo,
<script>
function f() {
console.log("foo");
setTimeout(g, 0);
console.log("foo again");
}
function g() {
console.log("bar");
}
function b() {
console.log("bye");
}
f();
/*<---- Is the stack empty here? */
b();
</script>
El orden correcto de ejecución es foo
- foo again
- bye
- bar
.
Pero hoy comencé a pensar: ¿no está la pila técnicamente vacía justo después de salir de la llamada f()
? Quiero decir que en ese momento no estamos dentro de ninguna función, y no hemos iniciado ninguna nueva ejecución, por lo que no se debe setTimeout
mensaje de llamada a setTimeout
(que se ha puesto inmediatamente en cola), antes de pasar a b()
, y dando la orden de foo
- foo again
- bar
- bye
?
¿Qué setTimeout(func, 0)
si tenemos un millón de líneas de código o algún cálculo intensivo para ejecutar y el setTimeout(func, 0)
en la cola por mucho tiempo?
Aunque el bloque de código dentro de las etiquetas <script>
no está envuelto en una función explícita, puede ser útil considerarlo como una función global que el navegador le dice al tiempo de ejecución de javascript que ejecute. Por lo tanto, la pila de llamadas no está vacía hasta que el código en el bloque de script termina de ejecutarse.
Cuando la pieza actual de Javascript que se está ejecutando haya finalizado y no tenga más instrucciones secuenciales para ejecutar, solo entonces el motor JS sacará el siguiente elemento de la cola de eventos.
Entonces, en tu ejemplo:
f();
b();
// JS is done executing here so this is where the next item will be
// pulled from the event queue to execute it
Javascript es de un solo hilo, lo que significa que el hilo actual de Javascript se ejecuta hasta su finalización, ejecutando todas las instrucciones dentro de una secuencia hasta que llega al final del código. Entonces, y solo entonces, saca el siguiente elemento de la cola de eventos.
Aquí hay algunas otras respuestas que pueden ayudarte a entender:
Cómo funcionan los temporizadores de Javascript
¿Cómo maneja JavaScript las respuestas AJAX en segundo plano? (Un montón de referencias de Event Loop en este post)
¿Debo preocuparme por las condiciones de carrera con Javascript asíncrono?
¿Los controladores de eventos JS pueden interrumpir la ejecución de otro controlador?
La explicación más simple posible: cuando todo el código síncrono en el script, función o controlador de eventos actual haya terminado de ejecutarse.
Para responder directamente "qué setTimeout
si tengo millones de líneas ..." Sí: su llamada a setTimeout
está bloqueada en la cola y esperará su turno.
La mejor manera de pensar para explicarlo es que la pila de llamadas no está vacía hasta que el código termina de ejecutar todas las rutas relevantes. Un setTimeout de 0 simplemente empuja su código al final de la pila.
Cuando el código se ejecuta en el tiempo de ejecución, todo lo que se ejecutará es parte de la pila de llamadas, el orden se ajustará en función del orden en que se llamen y de los métodos de tiempo de espera / intervalos / asíncronos que se llamen.
Algunos ejemplos:
function foo() {
console.log(''foo'');
}
function bar() {
baz();
console.log(''bar'');
}
function baz() {
setTimeout(function() { console.log(''timeout'') }, 0);
console.log(''baz'');
}
foo();
baz();
// call stack ends here, so, timeout is logged last.
// in console
// foo
// baz
// timeout
Como puede ver, la barra no se incluye en la pila de tiempo de ejecución porque no se llama. Si tenemos algo de HTML:
<div onclick="bar()">Bar runs</div>
Cuando haga clic en esa división, verá baz
, bar
, luego timeout
registrado en la consola porque el tiempo de espera siempre se empuja al final de los procesos en ejecución / pila de llamadas actualmente en ejecución.
Espero que esta explicación ayude!