Understanding the event loop's queue programmatically does not have a standard method. To determine the placement of an event in the queue, one must consider when it was added relative to other events and the classification of different types of events within the event loop.
In JavaScript within modern environments, there are two types of queuing mechanisms for deferred actions: The primary event loop (consisting of "macrotasks") and a secondary loop that executes at the end of each main task to handle any "microtasks" scheduled by the macrotask. Additionally, browsers incorporate requestAnimationFrame
(RAF) as a separate entity from the event loops, although still synchronized with them.
Commonly encountered event handlers such as setTimeout
, DOM events, etc., fall under the category of "macrotasks" executed in the main event loop.
Completion handlers of Promises belong to "microtasks" and are run immediately after the corresponding macrotask in which they were queued, preceding any subsequent macrotasks even if chronologically queued later.
RAF callbacks are triggered between macrotasks right before the browser repaints, surpassing the chronological order of macrotasks, including those queued prior to the requestAnimationFrame
callback.
For instance:
function run() {
requestAnimationFrame(function() {
log("RAF 1");
});
function log(msg) {
var p = document.createElement("pre");
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
setTimeout(function() {
log("timeout 1");
Promise.resolve().then(function() {
log("resolution 2 -- before timeout 2");
});
}, 0);
setTimeout(function() {
log("timeout 2");
requestAnimationFrame(function() {
log("RAF 2");
});
}, 0);
setTimeout(function() {
log("timeout 3");
requestAnimationFrame(function() {
log("RAF 3");
});
}, 0);
Promise.resolve().then(function() {
log("resolution 1");
});
}
function tick() {
document.body.innerHTML = "";
run();
setTimeout(tick, Math.random() * 800);
}
tick();
pre {
margin-top: 0;
margin-bottom: 0;
}
Observing the example above, you'll notice that while timeouts and promise resolutions are consistently ordered, RAF callbacks may interject at varying points, often towards the conclusion but not exclusively so.
Additionally, observe how the microtask of promise resolutions precede the execution of subsequent macrotasks.