Desarrollo y Mantenimiento de Sistemas Informáticos

4º. 1er cuatrimestre. Itinerario de Sistemas de la Información. Grado en Ingeniería Informática. ULL


GH Org   - GH Template Org   - GitHub Classroom   - Discussions   - Teams   - Campus ULL   - Students Activity   - Chat   - Google Meet

The JS Event Loop

Introducción

All JavaScript environments use an event loop

As long as there’s something left to do, JSs event loop will keep spinning. Whenever an event occurs, JS invokes any callbacks (event handlers) that are listening for that event.

The general algorithm of the JS Engine is like this:

executeSequentially(mainTask);
while (thereArePendingTasks()) do
  let oldestFinishedTask = waitUntilSomeTaskIsReady();
  executeSequentially(oldestFinishedTask);
end do

There’s an endless loop, when JavaScript engine waits for tasks, executes them and then sleeps waiting for more tasks

When JS runs in the browser:

Quote from MDN:

Each message is processed completely before any other message is processed […] A downside of this model is that if a message takes too long to complete, the web application is unable to process user interactions like click or scroll. The browser mitigates this with the “a script is taking too long to run” dialog. A good practice to follow is to make message processing short and if possible cut down one message into several messages.

MDN utiliza la terminología cola de mensajes para la cola de callbacks:

A JavaScript runtime uses a message queue, which is a list of messages to be processed. Each message has an associated function which gets called in order to handle the message.

Unas Preguntas

La pila de LLamadas

console.trace muestra la stack trace en la consola. la stack trace es el camino de las llamadas hasta el punto: nombre-de-rutina camino-hasta-el-fichero-del-programa:nº de línea:nº de columna}

¿Cual es la salida de las llamadas a console.trace?

function multiply(x,y) {
  // console.trace imprime una traza de la pila
  console.trace("-----------At multiply-----------");
  return x * y;
}

function squared(n) {
  console.trace("-----------At squared-----------");
  return multiply(n,n)
}

function printSquare(n) {
   return squared(n)
}

let numberSquared = printSquare(5);
console.log(numberSquared);

Output from execution

Orden de Ejecución

¿En que orden ocurren las salidas?

  (function() {

    console.log('this is the start');

    setTimeout(function cb() {
      console.log('Callback 1: this is a msg from call back');
    }); // has a default time value of 0

    console.log('this is just a message');

    setTimeout(function cb1() {
      console.log('Callback 2: this is a msg from call back');
    }, 0);

    console.log('this is the end');

  })();

Hoist: Cual es la salida?

  console.log(hoist); 

  var hoist = 'The variable has been hoisted.';

¿Cual sería la salida de esta variante?

  console.log(hoist);

  hoist = 'The variable has been hoisted.'

Para responder a esta pregunta es conveniente tener claro el concepto de Hoisting en JS. Hoisting is a JavaScript mechanism where variables, function and class declarations are moved to the top of their scope before code execution. Hoisting only moves the declaration. The assignments are left in place.

The scope of a variable declared with the keyword var is its current execution context. This is either the enclosing function or for variables declared outside any function, global.

Véase Understanding Hoisting in JavaScript by Mabishi Wakio

Hoisting y Asíncronía ¿Cual es la salida?

  for(var i=0;i<=3; i++) {
      setTimeout(()=> console.log(i), 0)
  }

(tema1-introduccion/practicas/p2-t1-c3-file-system/event-loop/var.js)

JS is single threaded

¿Cual es la salida?

  const s = new Date().getSeconds();

  setTimeout(function() {
    console.log("Ran after " + (new Date().getSeconds() - s) + " seconds");
  }, 500);

  while(true) {
    if(new Date().getSeconds() - s >= 2) {
      console.log("Good, looped for 2 seconds");
      break;
    }
  }

Repasando las Preguntas a la luz del Bucle de Eventos

Ejemplo: La Pila de Llamadas

Este ejemplo es tomado del vídeo:

se le puede proporcionar a loupe:

Este es el código:

function multiply(x,y) {
  // console.trace imprime una traza de la pila
  console.trace("-----------At multiply-----------");
  return x * y;
}

function squared(n) {
  console.trace("-----------At squared-----------");
  return multiply(n,n)
}

function printSquare(n) {
   return squared(n)
}

let numberSquared = printSquare(5);
console.log(numberSquared);

Output from execution

Orden de Ejecución

Ejemplo sacado del Tutorial Concurrency model and Event Loop at https://developer.mozilla.org

(function() {

  console.log('this is the start');

  setTimeout(function cb() {
    console.log('Callback 1: this is a msg from call back');
  }); // has a default time value of 0

  console.log('this is just a message');

  setTimeout(function cb1() {
    console.log('Callback 2: this is a msg from call back');
  }, 0);

  console.log('this is the end');

})();

Ejemplo: JS is single threaded

En mi máquina:

tema1-introduccion/practicas/p2-t1-c3-file-system/event-loop/settimeout-does-not-run-inmediately.js 

Tomado del tutorial:

Primero, un ejemplo, para entender el funcionamiento de Datey getSeconds:

[~/.../p2-t1-c3-file-system/event-loop(master)]$ node
Welcome to Node.js v12.10.0.
Type ".help" for more information.
> d = new Date()
2020-02-16T10:07:51.682Z
> s = d.getSeconds()
51
> e = new Date()
2020-02-16T10:07:57.992Z
> e.getSeconds()-d.getSeconds()
6

¿Cual es la salida?

const s = new Date().getSeconds();

setTimeout(function() {
  console.log("Ran after " + (new Date().getSeconds() - s) + " seconds");
}, 500);

while(true) {
  if(new Date().getSeconds() - s >= 2) {
    console.log("Good, looped for 2 seconds");
    break;
  }
}

Race Condition

See the examples:

The Event Loop en el libro The Modern JavaScript Tutorial

The section Concurrency model and the event loop at https://developer.mozilla.org/

References