Saltar a un capítulo clave
Comprender el Bucle de Eventos de Javascript
El Bucle de Eventos de JavaScript, en esencia, es un mecanismo que gestiona la ejecución de múltiples hilos, permitiendo que JavaScript parezca multihilo a nivel de máquina, aunque en realidad no lo sea.
¿Qué es un bucle de eventos en JavaScript?
JavaScript es un lenguaje monohilo, lo que significa que procesa una tarea a la vez mientras mantiene otras en una cola. El concepto de este sistema de colas nos lleva al Bucle de Eventos de JavaScript. Se trata de un ciclo de un proceso en constante ejecución que permite gestionar las llamadas de retorno asíncronas de forma sincronizada.Piensa en ello como en un restaurante concurrido. La cocina (el motor de javascript) sólo puede gestionar un pedido (función/tarea) a la vez, mientras que los pedidos restantes se ponen en cola. El Bucle de Eventos es el sistema del restaurante que comprueba si la cocina está lista para tomar otro pedido.
Funciones básicas del Bucle de Eventos de Javascript
El Bucle de Eventos de Javascript tiene varias funcionalidades cruciales. Éstas son:- Mantiene una cola de tareas.
- Supervisa la pila de ejecución y comprueba su disponibilidad para ejecutar una nueva tarea.
- Cuando la pila de ejecución está vacía, permite que se ejecute la primera tarea de la cola de tareas.
- Y repite este proceso indefinidamente, permitiendo a Javascript manejar múltiples tareas y llamadas de retorno sin problemas.
¿Cómo funciona el bucle de eventos de JavaScript?
El funcionamiento del Bucle de Eventos de Javascript se entiende mejor en cuatro etapas:- Creación del marco de pila: Se crea la función main() (o contexto global) y se introduce en el Marco de Pila actual.
- Ejecución inicial del código: El navegador comienza a leer y ejecutar el código línea a línea.
- Cola de llamadas de retorno: Las funciones asíncronas (como setTimeout) se envían a una API Web y se introducen en la cola de llamadas de retorno una vez completadas.
- Comprobación del bucle de eventos: Cuando el Marco de Pila está vacío, lo que significa que se ha leído todo el código, el bucle de eventos comprueba la Cola de Llamadas de Retorno. Si no está vacía, las funciones se retiran de la cola y se introducen en el Marco de Pila para su ejecución.
El tiempo de ejecución de JavaScript contiene una cola de mensajes, que es una lista de mensajes que deben procesarse. Cada mensaje tiene una función asociada a la que se llama para gestionar el mensaje. En algún momento del bucle de eventos, el tiempo de ejecución comienza a gestionar los mensajes de la cola, empezando por el más antiguo. Para tratar el mensaje, se llama a la función asociada con el mensaje como parámetro de entrada. En cuanto la pila vuelve a estar vacía, se comprueba si hay alguna función de retardo temporizada pendiente y, si la hay, se ejecuta esa función (como una función de retardo de setTimeout), con lo que se inicia la ejecución de un nuevo mensaje. Así, aunque JavaScript sea monohilo, puede hacer concurrencia gracias al bucle de eventos y a las API del navegador o de Node.js.
function main() { console.log('Hola'); setTimeout(function cb1() { console.log('cb1'); }, 5000); console.log('Adiós'); } main(); // Salida // "Hola" // "Adiós" // "cb1" tras 5 segundosEn el ejemplo de código anterior, primero llamamos a la función main. Tiene tres pasos: primero, registra "Hola" en la consola, después establece un tiempo de espera de 5 segundos, tras el cual registrará "cb1", y por último, registra "Adiós". Como JavaScript sólo tiene una pila de llamadas, maneja estas operaciones una tras otra. Por tanto, primero se registrará "Hola", luego "Adiós" y, por último, una vez transcurridos 5 segundos, "cb1". Aunque la función setTimeout haya sido llamada en segundo lugar, no impide que se ejecute el resto del código: este comportamiento no bloqueante se debe al bucle de eventos.
Explorar ejemplos de bucle de eventos en JavaScript
Comprender el funcionamiento de los bucles de eventos de JavaScript puede ser a veces una tarea desalentadora. Para ayudar a desmitificar los conceptos, vamos a explorar un par de ejemplos. Lo abordaremos en dos pasos: un ejemplo sencillo de Bucle de Eventos y, a continuación, uno más complejo.Ejemplo de bucle de eventos simple en JavaScript
Imagina un código JavaScript muy sencillo que imprima una cadena tras un cierto retardo. A continuación tienes un ejemplo de este código en acción:setTimeout(function() { console.log("Hola después de
3 segundos"); }, 3000);Cuando se ejecuta este fragmento de código, la consola permanece vacía y espera 3 segundos antes de que se imprima "Hola después de 3 segundos"'. Este retraso se produce debido a la naturaleza del mecanismo de bucle de eventos de JavaScript. He aquí cómo lo consigue JavaScript:
- Una vez que la función setTimeout se encuentra en el código, al tratarse de una API Web, se envía fuera de la pila de llamadas a una API Web de Temporizador.
- Este Temporizador cuenta durante 3000 milisegundos.
- Cuando el temporizador termina de contar, envía la función especificada en setTimeout a una cola de devolución de llamada.
- El Bucle de Eventos, que se estaba ejecutando indefinidamente, comprueba si la pila de llamadas está vacía.
- Una vez vacía, retira la función de la cola de llamadas de retorno y la coloca en la pila de llamadas para su ejecución.
Ejemplo de bucle de eventos complejo en JavaScript
Consideremos ahora un escenario más complejo. Imagina un script que establece dos tiempos de espera: uno que imprime inmediatamente y otro que imprime al cabo de un segundo: setTimeout(function() { console.log("Hola"); }, 0); setTimeout(function() { console.log("Hola al cabo de 1 segundo"); }, 1000);En este caso, a pesar de que la primera función setTimeout tiene un tiempo de retardo de cero milisegundos, no imprimirá inmediatamente. En lugar de eso, se traslada al entorno de la API Web y, una vez completado el retardo, se introducirá en la cola de llamadas de retorno. Mientras tanto, el motor de JavaScript ve la segunda función setTimeout y pasa a ella. Una vez que ambas funciones setTimeout completadas regresan de las API web, se envían a la Cola de Llamadas de Retorno. El orden de ejecución de las funciones en la cola de llamadas de retorno viene determinado por su orden de finalización. Por último, el bucle de eventos supervisa continuamente la pila de llamadas y la cola de llamadas de retorno. Cuando la pila de llamadas está vacía y la cola de llamadas de retorno tiene funciones ejecutables, las mueve a la pila para su ejecución. Por lo tanto, al principio se imprimirá "Hola después de 1 segundo", y después se imprimirá "Hola". Durante todo este proceso, el Bucle de Sucesos da prioridad a asegurarse de que la pila de llamadas se vacía lo antes posible antes de que pueda recibir cualquier mensaje entrante de la cola de mensajes. Por eso, aunque se establezca en cero segundos, la primera llamada de retorno de la función setTimeout no se ejecuta inmediatamente. Espera a que se complete todo el script, demostrando cómo el Bucle de Eventos da mayor prioridad a la pila de llamadas que a los mensajes en cola. Esta interacción entre la Pila de Llamadas, la API Web, la Cola de Llamadas de Retorno y el Bucle de Eventos es la quintaesencia del funcionamiento del entorno de ejecución de JavaScript y es esencial para comprender cómo funciona el código asíncrono en JavaScript.
Bucle de eventos y pila de llamadas de Javascript
JavaScript es un lenguaje monohilo, pero gracias a la interacción entre el Bucle de Eventos y la Pila de Llamadas, puede manejar múltiples tareas con un alto grado de eficacia.Comprender la relación entre la pila de llamadas y el bucle de eventos de JavaScript
El entorno de ejecución de JavaScript tiene dos elementos clave: la Pila de Llamadas y el Bucle de Eventos. Son responsables de la forma en que JavaScript gestiona la ejecución del código. Profundicemos en su relación y funcionamiento. La Pila de Llamadas es una estructura de datos que registra el contexto de ejecución de las funciones. Cuando se llama a una función de JavaScript, se coloca, o "empuja", en la Pila de Llamadas. A continuación, el motor de JavaScript la ejecuta. Una vez finalizada la ejecución de la función, se "saca" de la pila. Si hay una función dentro de otra función, la función interna se introduce en la pila y se convierte en la función que se está ejecutando en ese momento. Por otro lado, el Bucle de Eventos es un proceso que se ejecuta continuamente y que comprueba si la Pila de Llamadas está vacía. Si la Pila de Llamadas está vacía y la Cola de Llamadas de Retorno no lo está, empuja la primera función de llamada de retorno de la Cola de Llamadas de Retorno a la Pila de Llamadas. La importancia de la Pila de Llamadas para el Bucle de Sucesos es doble:- La Pila de Llamadas determina en gran medida cuándo el Bucle de Sucesos introduce nuevas rellamadas. Es decir, sólo cuando la pila está vacía, el bucle de eventos mueve funciones de la Cola de Llamadas de Retorno a la Pila de Llamadas.
- Mientras se ejecuta una función, la Pila de Llamadas está "ocupada", y el Bucle de Sucesos no añadirá más a ella. Es decir, si una función tarda demasiado en ejecutarse, puede bloquear la Pila de Llamadas e impedir que se ejecute otro código.
() { console.log('Función Uno'); function functionTwo() { console.log('Función Dos'); } functionTwo(); } functionOne(); // Salida: // Función Uno // FunciónDos Tanto functionOne como functionTwo se añaden a la Pila de Llamadas a medida que son llamadas, y se eliminan una vez completadas. Como la funciónDos fue llamada dentro de la funciónUno, se añadió a la parte superior de la pila y se convirtió en la función que se estaba ejecutando en ese momento.
¿Cómo influye la Pila de Llamadas JavaScript en el Bucle de Eventos?
El comportamiento de la pila de llamadas de JavaScript tiene un impacto significativo en el bucle de eventos. Debido a la naturaleza monohilo de JavaScript, la Pila de Llamadas sólo puede contener un contexto de ejecución de función a la vez, lo que influye en cuándo y cómo procesa las tareas el Bucle de Eventos. El Bucle de Eventos comprueba constantemente si la Pila de Llamadas está vacía. Si lo está, y si hay funciones de llamada de retorno esperando en la Cola de Llamadas de Retorno, esas funciones se introducen en la pila. Sin embargo, si la Pila de Llamadas no está vacía, estas llamadas de retorno tienen que esperar, incluso si la función que se está ejecutando en ese momento está tardando mucho en completarse. En un escenario así, asistimos a lo que se conoce comúnmente como "bloqueo". Un bloque de código que tarde mucho tiempo en ejecutarse, como un bucle grande o una función con grandes necesidades computacionales, puede detener el flujo de funciones de la Cola de Llamadas de Retrollamada a la Pila de Llamadas. Este fenómeno, conocido como bloqueo del bucle de eventos, es un problema de rendimiento habitual que debe evitarse para una ejecución fluida del código JavaScript.for (let i = 0; i < 1000000000; i++) { console.log("Código bloqueante"); } setTimeout(function() { console.log("Código no bloqueante"); }, 0);En el ejemplo anterior, el bucle puede bloquear la pila de llamadas mientras se ejecuta. El mensaje "Código no bloqueante" no se imprimirá hasta después de que termine el bucle for, aunque el retardo setTimeout esté fijado en 0 segundos. Esto muestra cómo el estado "ocupado" de la pila de llamadas afecta al Bucle de Eventos. En conclusión, el comportamiento de la Pila de Llamadas influye significativamente en la eficacia del Bucle de Eventos, lo que repercute en el rendimiento percibido de una aplicación JavaScript. Si comprendes esta relación, podrás escribir un código JavaScript mejor y más eficaz.
Mecanismo del Bucle de Eventos en JavaScript
El Bucle de Eventos es el corazón de toda aplicación JavaScript, responsable de gestionar la ejecución de los scripts y la renderización en los navegadores. Para apreciar plenamente su importancia y comprender cómo el código JavaScript se ejecuta de forma asíncrona a pesar de ser monohilo, profundicemos en el mecanismo del Bucle de Eventos y su temporización.Desglosando el mecanismo del Bucle de Eventos de JavaScript
En el núcleo de su mecanismo, el Bucle de Eventos gestiona la ejecución de múltiples trozos de tu código JavaScript. Cada trozo de este código puede ser una función, un script o un evento desencadenado por un usuario o una API Web. Para entender el mecanismo, desentrañemos los componentes del modelo de concurrencia de JavaScript, que son componentes esenciales del entorno de ejecución de JavaScript:Pila de llamadas: Es el lugar donde se ejecuta tu código JavaScript, una operación cada vez. Cuando una línea de código está lista para ejecutarse, se añade (o "empuja") a la Pila de Llamadas. Y cuando termina de ejecutarse, se retira (o 'salta') de la pila.APIs Web: Son bibliotecas incorporadas que proporciona el navegador, para operaciones que el propio lenguaje JavaScript no maneja. Cuando finaliza una operación de una API Web (como una solicitud de obtención o un temporizador), añade un mensaje a la Cola de Llamadas de Retorno. Cola de llamadas de retorno: Una vez que una función finaliza su operación en las API Web, se añade a esta cola. Las funciones se ponen en cola en el orden en que terminaron su ejecución en las APIs de la Web. Por último, esto es lo que hace el Bucle de Eventos: - Comprueba si hay una operación esperando en la Pila. Si la Pila está vacía, mueve la primera operación de la Cola de Llamadas de Retrollamada a la Pila. - Este proceso continúa incesantemente, asegurándose de que cada función ejecutada obtiene el tiempo de CPU que necesita, y garantizando que las interacciones del usuario no se queden atascadas esperando en la Cola de Llamadas de Retrollamada durante demasiado tiempo. Así, el Bucle de Eventos mantiene el equilibrio y la naturaleza no bloqueante de tu código JavaScript.Comprender la Temporización en el Mecanismo JavaScript de Bucle de Eventos
Comprender la temporización del mecanismo de Bucle de Eventos es crucial para escribir código JavaScript eficiente y no bloqueante. Profundicemos en los factores clave de temporización:- Retrasos Cero: Uno de los principales conceptos erróneos sobre las funciones de temporizador de JavaScript, como setTimeout(), es que el parámetro de tiempo representa un tiempo de espera exacto para la ejecución de su función de devolución de llamada. Sin embargo, no es así.
(() => { console.log('Hola Mundo'); }, 0);El código anterior no garantiza que 'Hola Mundo' se imprima exactamente después de 0 milisegundos. Esto se debe a que la temporización no tiene en cuenta el tiempo que tardan la Pila de Llamadas, el Bucle de Eventos y la Cola de Llamadas de Retorno en procesar otras operaciones. Cuando el Bucle de Eventos saca la función de llamada de retorno de la Cola de Llamadas de Retorno y la coloca en la Pila de Llamadas, sólo lo hace cuando la Pila está vacía. Esto puede crear un retraso.
- Orden deejecución:En el Bucle de Eventos, el orden de ejecución no sigue necesariamente el orden de la Pila de Llamadas. En su lugar, está dictado por el orden de las operaciones en la Cola de Llamadas de Retorno. Cuando finalizan las operaciones que se han enviado a las API Web, se añaden a la Cola de Llamadas de Retorno. El Bucle de Eventos recoge las operaciones de la Cola de Llamadas de Retorno en el orden en que fueron añadidas.
setTimeout(() => { console.log('Primera'); }, 2000); setTimeout(() => { console.log('Segunda'); }, 1000);Aunque 'Primera' aparece antes que 'Segunda' en el código y, por tanto, en la Pila de Llamadas en primer lugar, 'Segunda' se imprimirá antes que 'Primera'. Esto se debe a que el bucle de eventos enviará "Segundo" a la cola de llamadas de retorno antes que "Primero", ya que tiene un retardo menor. Comprender estos matices y factores de tiempo puede mejorar significativamente tu dominio de JavaScript. Durante todo el proceso, el Bucle de Eventos garantiza la ejecución fluida de las tareas, manteniendo la concurrencia en el entorno de un solo hilo de JavaScript.
El bucle de eventos de JavaScript en la programación asíncrona
Aunque JavaScript es inherentemente monohilo, su capacidad para manejar tareas de forma asíncrona es una de sus características más llamativas. La magia que hay detrás de esta característica se debe principalmente al Bucle de Eventos de Javascript.Papel del Bucle de Eventos de Javascript en la Programación Asíncrona
El respeto que despierta Javascript como lenguaje robusto y versátil se debe en gran medida a su capacidad para funcionar sin problemas en diversos medios, como navegadores y servidores, y esto se debe en gran medida a su comportamiento asíncrono. La capacidad asíncrona se debe a la funcionalidad del Bucle de Eventos, basada en el entorno de ejecución de JavaScript, donde trabaja junto a estructuras como la Pila de Llamadas y la Cola de Llamadas de Retorno. La programación asíncrona permite a JavaScript ejecutar tareas fuera del flujo principal del programa sin bloquear la ejecución del código posterior. Esta naturaleza no bloqueante garantiza que tu programa no quede bloqueado, esperando a que se completen tareas como peticiones de red o temporizadores, mientras hay otro código que podría estar ejecutándose. Ahí es donde el papel del Bucle de Eventos es crucial, ya que su función es controlar constantemente la Pila de Llamadas y la Cola de Llamadas de Retorno. Si la Pila de Llamadas está vacía, toma la primera tarea de la Cola de Llamadas de Retorno y la coloca en la Pila de Llamadas para su ejecución. Este sencillo proceso es lo que permite el comportamiento asíncrono en JavaScript. Cualquier función que deba ejecutarse de forma asíncrona, como setTimeout o fetch, se envía a un módulo de la Web API (como el temporizador o el módulo de solicitud HTTP, incorporado en el navegador). Una vez completada la operación de la API Web, se introduce una función de llamada de retorno en la cola de llamadas de retorno. A continuación, el Bucle de Eventos se asegura de que estas funciones de devolución de llamada se envíen de nuevo a la Pila de Llamadas cuando esté lista para más tareas.Comprender la programación asíncrona mediante ejemplos de bucles de eventos en Javascript
Entender el Bucle de Eventos a través de ejemplos prácticos de código puede ayudar a consolidar el concepto. Exploremos algunos ejemplos para demostrar cómo el Bucle de Eventos gestiona el código JavaScript asíncrono. En el sencillo ejemplo siguiente, una función de temporizador se ejecuta de forma asíncrona, por lo que no bloquea la ejecución del log 'After setTimeout'.console.log('Antes de setTimeout'); setTimeout(() => { console.log('Dentro de setTimeout'); }, 0); console.log('Después de setTimeout');En la salida, observarás que 'Dentro de setTimeout' se imprime en último lugar, a pesar de un retraso de 0 milisegundos. Esto se debe al bucle de eventos. Aunque "Dentro de setTimeout" forma parte de la función setTimeout, se pasa a la API Web, liberando la Pila de Llamadas. La Pila de Llamadas pasa a ejecutar 'Después de setTimeout'. Sólo cuando la Pila de Llamadas está libre y el temporizador se ha completado, el Bucle de Eventos mueve "Dentro de setTimeout" de la Cola de Llamadas de Retorno a la Pila de Llamadas para su ejecución. Comprender el papel del Bucle de Eventos en este escenario explica por qué el JavaScript asíncrono funciona como lo hace. Aunque parece que la función setTimeOut debería mostrar "Dentro de setTimeout" antes que "Después de setTimeout", no es así. Examinemos otro ejemplo:
console.log('Antes de la solicitud de búsqueda'); fetch('https://jsonplaceholder.typicode.com/posts') .then(() => console.log('Búsqueda correcta')) .catch(() => console.log('Búsqueda fallida')); console.log('Después de la solicitud de búsqueda');En este caso, la solicitud de búsqueda se gestiona de forma asíncrona, de forma similar a la función setTimeout. Al llamar a fetch, se descarga a una API Web (el módulo de peticiones HTTP), dejando que la Pila de Llamadas pase a 'After fetch request'. La llamada de retorno '.then()' sólo se envía a la cola de llamadas de retorno cuando finaliza la operación de obtención. Aunque el recurso tarde en obtenerse de la URL, el resto del programa sigue ejecutándose sin esperar a que se complete la solicitud de obtención. El Bucle de Eventos, una vez más, gestiona esto sin problemas. A partir de estos ejemplos, queda clara la función evolutiva del Bucle de Eventos de JavaScript: mantener tu código JavaScript sin bloqueos y funcionando sin problemas gestionando eficazmente la Pila de Llamadas y la Cola de Llamadas de Retorno en torno a las operaciones asíncronas.
Bucle de eventos de JavaScript - Puntos clave
- Bucle de Eventos Javascript: Un proceso en ejecución continua que comprueba si la Pila de Llamadas está vacía. Si lo está, y la cola de llamadas de retorno tiene funciones preparadas, las envía a la pila de llamadas para su ejecución.
- Pila de llamadas: Estructura de datos que registra el contexto de ejecución de las funciones en JavaScript. Las funciones se "introducen" en la Pila de Llamadas para su ejecución y se "extraen" una vez finalizada.
- Cola de llamadas de retorno: Las funciones que han completado su operación en las API Web se añaden a esta cola, donde esperan a ser ejecutadas.
- Comportamiento no bloqueante: Se consigue mediante el Bucle de Eventos, que permite a JavaScript continuar con otras tareas sin esperar a que se complete una tarea que consuma mucho tiempo (como setTimeout).
- API Web: Bibliotecas incorporadas proporcionadas por el navegador que gestionan operaciones no atendidas por el lenguaje JavaScript. Una vez que finaliza una operación, añade un mensaje a la cola de llamadas de retorno.
Aprende con 15 tarjetas de Bucle de eventos de Javascript en la aplicación StudySmarter gratis
¿Ya tienes una cuenta? Iniciar sesión
Preguntas frecuentes sobre Bucle de eventos de Javascript
Acerca de StudySmarter
StudySmarter es una compañía de tecnología educativa reconocida a nivel mundial, que ofrece una plataforma de aprendizaje integral diseñada para estudiantes de todas las edades y niveles educativos. Nuestra plataforma proporciona apoyo en el aprendizaje para una amplia gama de asignaturas, incluidas las STEM, Ciencias Sociales e Idiomas, y también ayuda a los estudiantes a dominar con éxito diversos exámenes y pruebas en todo el mundo, como GCSE, A Level, SAT, ACT, Abitur y más. Ofrecemos una extensa biblioteca de materiales de aprendizaje, incluidas tarjetas didácticas interactivas, soluciones completas de libros de texto y explicaciones detalladas. La tecnología avanzada y las herramientas que proporcionamos ayudan a los estudiantes a crear sus propios materiales de aprendizaje. El contenido de StudySmarter no solo es verificado por expertos, sino que también se actualiza regularmente para garantizar su precisión y relevancia.
Aprende más