Event Loop Notes

oswaldo.herrera@WIZELINE.com 

@wdonet

Is that simple ?

from   node.university

heard of it as ... ?

Heap

Event Loop

Stack

Execution Context

Memory Allocation

Callback queue

onfocus callback()

onload callback()

onclick callback()

Web APIs

DOM

XMLHttpRequest

setTimeout

call1()

call3()

call2()

static uv_thread_t default_threads[4];

#define MAX_THREADPOOL_SIZE 128

More big pictures

More complex yet

phases

  callbacks scheduled by

setTimeout() and setInterval()

 IO related callbacks except those scheduled by timers and setImmediate()

used internally

  setImmediate() callbacks

  i.e. socket.on('close', ...)

retrieve new I/O events

or ticks

callback

resolve promise

next scheduled tick

LIBUV

Timers Phase

A timer specifies a threshold

TIME

now

 

 

 

100ms

 The poll phase controls when timers are executed

(as early as possible after the threshold)


setTimeout(() => {}, 100);

Timers Phase

TIME

threshold

var fs = require('fs');

function someAsyncOperation (callback) {
  // Assume this takes 95ms to complete
  fs.readFile('/path/to/file', callback);
}

var timeoutScheduled = Date.now();
setTimeout(function () {
  var delay = Date.now() - timeoutScheduled;
  console.log(delay + "ms have passed since I was scheduled");
}, 100);


// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(function () {
  var startCallback = Date.now();
  // do something that will take 10ms...
  while (Date.now() - startCallback < 10) {
    ; // do nothing
  }
});

timeoutScheduled

100ms

setTimeout() callback

fs.readFile( f ) ends

95ms

10ms

f()

105ms

105ms have passed since I was scheduled

Timers Phase Demo

I/O callbacks Phase

executes callbacks for some

system operations

(network - disk files - database connections)

ECONNREFUSED

ETIMEDOUT

  i.e. TCP sockets

 

 

Poll Phase

Jump to Check Phase

 callback queue empty ?

Execute

do

WHILE

- callback exists, and

- OS hard limit not reached

YES

NO

NO

YES

 Is there a script scheduled by setImmediate() ?

Execute

all timers who reached threshold

NO

YES

Check Phase

execute callbacks (almost) immediately

after the poll phase has completed

setImmediate( callback() )

If poll phase becomes idle, executes

at the check phase .

Close Callbacks Phase

executes callbacks for

 

"close" events

 

 and for

 cleaning things

websocket.close()

EventEmitter.on('close', () => {})

  i.e. 

 

 

socket.end()

Event Loop Phases

  for  setTimeout() & setInterval()

  for  IO related callbacks

  for  setImmediate() callbacks

  for closing events

executes queued callback

( Again )

setTimeout()

setImmediate()

// timervsimmediate.js

setTimeout(function timeout () {
  console.log('timeout');
},0);

setImmediate(function immediate () {
  console.log('immediate');
});

setTimeout()

setImmediate()

// immediateOverTimer.js

var fs = require('fs')

fs.readFile(__filename, () => {

  setTimeout(() => {
    console.log('timeout')
  }, 0)

  setImmediate(() => {
    console.log('immediate')
  })

});

setImmediate() will always execute before any timer,

 if it is scheduled within an I/O cycle

process.nextTick()

callback

resolve promise

next scheduled tick

nextTickQueue()

micro tasks

Callback queue

scheduled callback()

scheduled callback()

scheduled callback()

happens inside the same phase

process.nextTick()

// this has an asynchronous signature, but calls callback synchronously
function someAsyncApiCall (callback) { callback(); };

// the callback is called before `someAsyncApiCall` completes.
someAsyncApiCall(() => {

  // since someAsyncApiCall has completed, bar hasn't been assigned any value
  console.log('bar', bar); // undefined

});

var bar = 1;
function someAsyncApiCall (callback) {
  process.nextTick(callback);
};

someAsyncApiCall(() => {
  console.log('bar', bar); // 1
});

var bar = 1;

would work ?

and this ?


function apiCall (arg, callback) {
  if (typeof arg !== 'string')
    return process.nextTick(callback,
      new TypeError('argument should be string'));
}

process.nextTick()

real life examples

const server = net.createServer(() => {}).listen(8080);

server.on('listening', () => {});

process.nextTick()

Executes at same phase

 

Main reasons:

- Cleaning : error handling, unnecessary resources cleaning   or re-try request

- Run operations before loop continues

setImmediate()

Executes at next tick (phase)

 

Compatible with browser JS and + environments

 

Easier to reason about

 

Event Loop Notes

By Oswaldo Herrera

Event Loop Notes

Event Loop notes that worth to share

  • 869