KEMBAR78
All you need to know about the JavaScript event loop | PPTX
All you need to know about the
JavaScript event loop
Saša Tatar @sasatatar
Front-end Dev at @codaxy
JavaScript Engine (e.g. V8)
• Heap
Objects are allocated in a heap which is just
a name to denote a large mostly
unstructured region of memory.
• Stack
Function calls form a stack of frames. Each
time a function is invoked, a new frame
containing its execution context (arguments
and local variables) is created and pushed
on top of the stack. Once the function
returns, the frame is popped off the stack.
Heap Stack
a first frame is created containing bar's arguments and local variables
The call stack
one thread => one call stack => one thing at a time
function foo(b) {
var a = 10;
debugger;
return a + b + 11;
}
function bar(x) {
var y = 3;
return foo(x * y);
}
bar(7);
Stack
(anonymous)
bar
foo
Call stack demo
Maximum call stack size excided => a.k.a. stack overflow
function foo(a) {
console.log(a++);
foo(a);
}
foo(0);
Stack
foo
foo
foo
foo
foo
foo
foo
JS Engine + Web API + Callback Queue
= JavaScript Runtime
Imagine a robot is playing a music:
• The JavaScript code would be the music notes to the
robot.
• The JavaScript engine would be the robot which can
understand the notes and act on it.
• The Web API would be the instruments the robot can
use in order to play the music.
Imagine a robot is putting out a fire:
• The JavaScript code would be the instructions for the
robot to put out a fire.
• The JavaScript engine would be the robot which can
understand the instructions and act on it.
• The Web API would be the fire truck, and the water
gun.
Stack
Web API
DOM
ajax
setTimeout
Callback Queue
Event loop - simplified
JavaScript Event Loop
Is queue
empty?
Process
one task
Is queue
empty?
No
Process
one task
Is rendering
needed?
Update
rendering
Yes
No
Yes
No
Yes
Macrotask queue
Microtask queue
DOM mutations Promises
Network
events
HTML
parsing
Keyboard
events
Mouse
events
Full loop completes at least every 16.67 ms.
callback
Example with setTimeout(callback, delay)
console.log(1);
setTimeout(function callback() {
console.log(2)
}, 0);
console.log(3);
stack
Web API
callback queue
(anonymous)
setTimeout(callback, 0);
callback
CONSOLE:
> 1
> 3
> 2
What about Promises?
function sleep(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
console.log('Doing some work (occupying the stack)...');
}
}
setTimeout(() => console.log('Timeout fires'), 0);
var p = new Promise((resolve, reject) => resolve());
sleep(200);
p.then(() => console.log('Promise resolved'));
JavaScript Event Loop
Is queue
empty?
Process
one task
Is queue
empty?
No
Process
one task
Is rendering
needed?
Update
rendering
Yes
No
Yes
No
Yes
Macrotask queue
Microtask queue
DOM mutations Promises
Network
events
HTML
parsing
Keyboard
events
Mouse
events
What about Promises?
function sleep(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
console.log('Doing some work (occupying the stack)...');
}
}
setTimeout(() => console.log('Timeout fires'), 0);
var p = new Promise((resolve, reject) => resolve());
sleep(200);
p.then(() => console.log('Promise resolved'));
Dealing with computationally expensive processing
// A long running task:
<table><tbody></tbody></table>
<script>
const tbody = document.querySelector("tbody");
for (let i = 0; i < 20000; i++) {
const tr = document.createElement("tr");
for (let t = 0; t < 6; t++) {
const td = document.createElement("td");
td.appendChild(document.createTextNode(i + "," + t));
tr.appendChild(td);
}
tbody.appendChild(tr);
}
</script>
creates an
individual row
for each row, creates 6
cells, each with a text node
attaches the new
row to its parent
Divide and conquer
const rowCount = 20000;
const divideInto = 4;
const chunkSize = rowCount/divideInto;
let iteration = 0;
const table = document.getElementsByTagName("tbody")[0];
setTimeout(function generateRows(){
const base = chunkSize * iteration;
for (let i = 0; i < chunkSize; i++) {
const tr = document.createElement("tr");
for (let t = 0; t < 6; t++) {
const td = document.createElement("td");
td.appendChild(
document.createTextNode((i + base) + "," + t + "," + iteration));
tr.appendChild(td);
}
table.appendChild(tr);
}
iteration++;
if (iteration < divideInto)
setTimeout(generateRows, 0);
}, 0);
We divide the rows in 4 smaller
chunks, 5000 rows each.
Compute where we left off last
time.
Schedules the next
phase
Set time-out delay to 0 to indicate that
the next iteration should execute ASAP,
but after the DOM has been updated.
Throttle and debounce
function throttle(callback, delay) {
let timer, context, args;
return function () {
context = this;
args = arguments;
if (!timer)
timer = setTimeout(function () {
callback.apply(context, args);
timer = null;
}, delay);
};
}
function debounce(callback, delay) {
let timer;
return function () {
let context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
callback.apply(context, args);
}, delay);
};
}
That’s it!
Further reading/resources:
• https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
• Philip Roberts: What the heck is the event loop anyway? | JSConf EU
• http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/
• Secrets of the JavaScript Ninja, J. Resig, B. Bibeault, J. Maras
• https://css-tricks.com/debouncing-throttling-explained-examples/

All you need to know about the JavaScript event loop

  • 1.
    All you needto know about the JavaScript event loop Saša Tatar @sasatatar Front-end Dev at @codaxy
  • 2.
    JavaScript Engine (e.g.V8) • Heap Objects are allocated in a heap which is just a name to denote a large mostly unstructured region of memory. • Stack Function calls form a stack of frames. Each time a function is invoked, a new frame containing its execution context (arguments and local variables) is created and pushed on top of the stack. Once the function returns, the frame is popped off the stack. Heap Stack a first frame is created containing bar's arguments and local variables
  • 3.
    The call stack onethread => one call stack => one thing at a time function foo(b) { var a = 10; debugger; return a + b + 11; } function bar(x) { var y = 3; return foo(x * y); } bar(7); Stack (anonymous) bar foo
  • 4.
  • 5.
    Maximum call stacksize excided => a.k.a. stack overflow function foo(a) { console.log(a++); foo(a); } foo(0); Stack foo foo foo foo foo foo foo
  • 6.
    JS Engine +Web API + Callback Queue = JavaScript Runtime Imagine a robot is playing a music: • The JavaScript code would be the music notes to the robot. • The JavaScript engine would be the robot which can understand the notes and act on it. • The Web API would be the instruments the robot can use in order to play the music. Imagine a robot is putting out a fire: • The JavaScript code would be the instructions for the robot to put out a fire. • The JavaScript engine would be the robot which can understand the instructions and act on it. • The Web API would be the fire truck, and the water gun. Stack Web API DOM ajax setTimeout Callback Queue Event loop - simplified
  • 7.
    JavaScript Event Loop Isqueue empty? Process one task Is queue empty? No Process one task Is rendering needed? Update rendering Yes No Yes No Yes Macrotask queue Microtask queue DOM mutations Promises Network events HTML parsing Keyboard events Mouse events Full loop completes at least every 16.67 ms.
  • 8.
    callback Example with setTimeout(callback,delay) console.log(1); setTimeout(function callback() { console.log(2) }, 0); console.log(3); stack Web API callback queue (anonymous) setTimeout(callback, 0); callback CONSOLE: > 1 > 3 > 2
  • 9.
    What about Promises? functionsleep(miliseconds) { var currentTime = new Date().getTime(); while (currentTime + miliseconds >= new Date().getTime()) { console.log('Doing some work (occupying the stack)...'); } } setTimeout(() => console.log('Timeout fires'), 0); var p = new Promise((resolve, reject) => resolve()); sleep(200); p.then(() => console.log('Promise resolved'));
  • 10.
    JavaScript Event Loop Isqueue empty? Process one task Is queue empty? No Process one task Is rendering needed? Update rendering Yes No Yes No Yes Macrotask queue Microtask queue DOM mutations Promises Network events HTML parsing Keyboard events Mouse events
  • 11.
    What about Promises? functionsleep(miliseconds) { var currentTime = new Date().getTime(); while (currentTime + miliseconds >= new Date().getTime()) { console.log('Doing some work (occupying the stack)...'); } } setTimeout(() => console.log('Timeout fires'), 0); var p = new Promise((resolve, reject) => resolve()); sleep(200); p.then(() => console.log('Promise resolved'));
  • 12.
    Dealing with computationallyexpensive processing // A long running task: <table><tbody></tbody></table> <script> const tbody = document.querySelector("tbody"); for (let i = 0; i < 20000; i++) { const tr = document.createElement("tr"); for (let t = 0; t < 6; t++) { const td = document.createElement("td"); td.appendChild(document.createTextNode(i + "," + t)); tr.appendChild(td); } tbody.appendChild(tr); } </script> creates an individual row for each row, creates 6 cells, each with a text node attaches the new row to its parent
  • 13.
    Divide and conquer constrowCount = 20000; const divideInto = 4; const chunkSize = rowCount/divideInto; let iteration = 0; const table = document.getElementsByTagName("tbody")[0]; setTimeout(function generateRows(){ const base = chunkSize * iteration; for (let i = 0; i < chunkSize; i++) { const tr = document.createElement("tr"); for (let t = 0; t < 6; t++) { const td = document.createElement("td"); td.appendChild( document.createTextNode((i + base) + "," + t + "," + iteration)); tr.appendChild(td); } table.appendChild(tr); } iteration++; if (iteration < divideInto) setTimeout(generateRows, 0); }, 0); We divide the rows in 4 smaller chunks, 5000 rows each. Compute where we left off last time. Schedules the next phase Set time-out delay to 0 to indicate that the next iteration should execute ASAP, but after the DOM has been updated.
  • 14.
    Throttle and debounce functionthrottle(callback, delay) { let timer, context, args; return function () { context = this; args = arguments; if (!timer) timer = setTimeout(function () { callback.apply(context, args); timer = null; }, delay); }; } function debounce(callback, delay) { let timer; return function () { let context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { callback.apply(context, args); }, delay); }; }
  • 15.
    That’s it! Further reading/resources: •https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop • Philip Roberts: What the heck is the event loop anyway? | JSConf EU • http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/ • Secrets of the JavaScript Ninja, J. Resig, B. Bibeault, J. Maras • https://css-tricks.com/debouncing-throttling-explained-examples/