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
Shim - setImmediate demo
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!');
The JavaScript Event Loop
By Yariv Gilad
The JavaScript Event Loop
- 2,213