while (queue.waitForMessage()) {
queue.processNextMessage();
}
ECMAScript specification is about:
* Syntactic and Lexical Grammars;
* Data Types and Values;
* Execution Contexts;
* Objects, Objects Behaviours;
* Functions and Classes;
* And etc.
has not any mention about events, timers, callbacks and etc.
is formally specified in HTML specification*
WHATWG. HTML Living standard
while (eventLoop.waitForTask()) {
eventLoop.processNextTask()
}
It is infinitely looping and looking for new tasks to execute.
To coordinate activities: events, user interaction, scripts, rendering, networking, and so forth, user agents
An event loop has one or more task queues.
Task queue is an ordered list of tasks
while (eventLoop.waitForTask()) {
const taskQueue = eventLoop.selectTaskQueue()
if (taskQueue.hasNextTask()) {
taskQueue.processNextTask()
}
}
It is an ordered list of tasks, which are algorithms that are responsible for such work as:
while (eventLoop.waitForTask()) {
const taskQueue = eventLoop.selectTaskQueue()
if (taskQueue.hasNextTask()) {
taskQueue.processNextTask()
}
const microtaskQueue = eventLoop.microTaskQueue
while (microtaskQueue.hasNextMicrotask()) {
microtaskQueue.processNextMicrotask()
}
}
The event loop also has a single queue called the microtask queue.
The microtask queue is completely emptied in every tick after the current task finished executing.
solitary callback microtasks
compound microtasks
Each event loop also has a performing a microtask checkpoint flag
while (eventLoop.waitForTask()) {
const taskQueue = eventLoop.selectTaskQueue()
if (taskQueue.hasNextTask()) {
taskQueue.processNextTask()
}
const microtaskQueue = eventLoop.microTaskQueue
while (microtaskQueue.hasNextMicrotask()) {
microtaskQueue.processNextMicrotask()
}
if (eventLoop.shouldRender()) {
eventLoop.render()
}
}
runTheResizeSteps()
runTheScrollSteps()
evaluateMediaQueriesAndReportChanges()
runCSSAnimationsAndSendEvents()
runTheFullscreenRenderingSteps()
runTheAnimationFrameCallbacks()
runTheUpdateIntersectionObservationsSteps()
intersectionObserverSteps()
paint()
Each worker has one event loop. Workers have restrictions *
A browsing context event loop always has at least one browsing context
There are two kinds of event loops
Browsing
Contexts
postMessage
postMessage
Web Worker
Task Queues
Task Queues
Web Worker
Task Queues
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
What this code will output to the console?
Little visualisation to help you understand how JavaScript's call stack/event loop/callback queue interact with each other.
Built by Philip Roberts. Code is on github.
<div class="outer">
<div class="inner" />
</div>
Result in the browser
We have the following HTML code
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');
new MutationObserver(function() {
console.log('mutate');
}).observe(outer, {
attributes: true
});
function onClick() {
console.log('click');
setTimeout(function() {
console.log('timeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise');
});
outer.setAttribute('data-random', Math.random());
}
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);
click
promise
mutate
click
promise
mutate
timeout
timeout
click
mutate
click
mutate
promise
promise
timeout
timeout
click
promise
mutate
click
promise
mutate
timeout
timeout
click
promise
mutate
click
promise
mutate
timeout
timeout
click
click
promise
promise
mutate
timeout
timeout
Google Chrome
Mozilla Firefox
Safari
IE Edge
click
mutate
click
mutate
promise
promise
timeout
timeout
click
promise
mutate
click
promise
mutate
timeout
timeout
click
promise
mutate
click
promise
mutate
timeout
timeout
click
click
promise
promise
mutate
timeout
timeout
* After article test (which posted 17 August 2015) only Safari browser behavior was successfully changed.
Mozilla Firefox was changed also, but it not correct according specification.
Google Chrome
Mozilla Firefox
Safari
IE Edge
const times = 1000
const processor = new Processor();
for (let i = 1; i < times; i++) {
// calculation time, for example 10ms
processor.calculate(i);
}
console.log(
processor.result()
)
It will lock up the Browser for 10 seconds
There's an example of long running code*
Make loop via setTimeout *
const calculate = (processor, times, callback) => {
let i = 1;
const tick = () => {
if (i < times) {
processor.calculate(i);
i++;
setTimeout(tick);
} else {
callback();
}
}
setTimeout(tick);
}
const processor = new Processor();
calculate(processor, 1000, () => {
console.log(processor.result());
})
Extract script. Use web worker API functions *
const worker = new Worker('/path/to/script.js');
worker.postMessage('start')
worker.onmessage = (e) => {
console.log(e.data)
}
// ..
self.addEventListener('message', (e) => {
if (e.data === 'start') {
for (let i = 1; i < times; i++) {
processor.calculate(i);
}
postMessage(
processor.result()
)
}
}, false);
Create Worker instance. Post "start" message