The
JavaScript
Event Loop

Event Loop

What do we know about JavaScript?

Event Loop

Rumor has it that JavaScript is... 

  • Great for serving many Concurrent connections 
  • Single threaded
  • Can be blocking and Non-blocking simultaneously…
  • Asynchronous by nature
  • and Async is so darn fast!

Event Loop

But what is JavaScript actually made of?

  • a runtime like V8 (heap/stack)
  • a call stack  
  • a callback queue 
  • an event loop
  • Browser - web api's (DOM, ajax, setTimeout...)

  • Node.js - bindings (file-system, network, other...)

Event Loop

The browser and Node

are NOT Single threaded,

but JavaScript is!

Event Loop

JavaScript is Single threaded

  • Benefits:  no locks, race conditions and threading overhead.
  • Implications:   a single thread  ===  a single call stack
  • Which means - JavaScript can play one thing at a time. 

Event Loop

 So what is this call stack?

The call stack determines

where we are in the program.

  • When we run a function,
    we push it to the stack.
     
  • When a function returns,
    we pop it off the top of the stack.

Event Loop

 The call stack

When errors occure,

we can examine the call stack

in the console. 

  • We see which functions have been called, and when that error happened.

Event Loop

 So JavaScript is actually blocking?

Well – it depends on the code we execute in the call stack…

for( let i = 0 ; i < 1000000000 ; i++ ) {
    //nothing will run until this loop ends…
} 
const now = new Date().getTime();

while (new Date().getTime() < now + 10000){
    //the thread is blocked for 10 seconds…
} 

Event Loop

So be careful, you only have
a single thread, try not to kill it...

Event Loop

  • The Call Stack is single threaded

  • async io calls run in other threads

  • Then added to the callback queue

  • Then executed in the stack once it is available

What about
Those callbacks
then?

Event Loop

Node.js has a very Similar Flow

Event Loop

The difference is exponential

Event Loop

The event loop scales really nice with all those Async i/o calls...

Event Loop

But what about those blocking operations in the call stack?

Event Loop

Classic example will be sorting very big data-structures

How can we make sure those will not to block the call stack?

Event Loop

Make it land in the callback queue

We can break down a long process to small "async"
chunks and use setTimeout() to avoid blocking

function longProcess(array,render){
    const items = [...array]; //clone the array

    const iterator = ()=> {
        const item = items.shift();
        render(item);

        if (items.length > 0) setTimeout(iterator, 0);
    }

    setTimeout(iterator, 0);
}

Between each process, we call setTimeout with 0 milliseconds delay,
giving the call stack a chance to execute and clear

Event Loop

SetTimeout() sets a minimum time

If the call-stack is not empty, it will finish running the code first
and only then process the callback queue…

Event Loop

So we can use     setTimeout(func,0)       to breakdown
long JS computation into small non-blocking operations

setTimeout(func,0)

The recommended way is to use    setImmediate(func);
suggested by Microsoft and implemented by Node.js

setImmediate(func)

for all browsers and old 0.9 Node.js

Event Loop

  • Use setImmediate
    to queue the function at the end of I/O callback queue.
     
  • Use process.nextTick() 
    to queue the function at the beginning of the callback queue.

setImmediate()  vs  process.nextTick()

So when breaking up a long running job using an iterator,
you want to use 
setImmediate rather than process.nextTick 
otherwise any I/O callbacks wouldn't get the chance to run between iterations.

Event Loop

Pop quiz...

What will we see in the console?

setTimeout( ()=> console.log('hello') , 0);
[...'world'].map( str => console.log(str) );
console.log('!');
console.log('Kick-off');
setTimeout(()=> console.log('timeout') , 0);

Promise.resolve()
	   .then(()=> console.log('promise 1') )
	   .then(()=> console.log('promise 2') )
	   .then(()=> console.log('promise 3') )

console.log('The end!');
console.log('Kick-off');
setImmediate(()=> console.log('setImmediate'));

Promise.resolve()
	   .then(()=> console.log('promise 1') )
	   .then(()=> console.log('promise 2') )
	   .then(()=> console.log('promise 3') )

console.log('The end!');
console.log('Kick-off');
process.nextTick(()=> console.log('nextTick'));

Promise.resolve()
	   .then(()=> console.log('promise 1') )
	   .then(()=> console.log('promise 2') )
	   .then(()=> console.log('promise 3') )

console.log('The end!');