Deep Dive into Promise Microtasks: How .then Registers and Executes
This article thoroughly dissects JavaScript Promise execution, revealing how microtasks are registered and run across multiple code snippets, compares Promise/A+ with WebKit implementations, and provides detailed code analyses and output predictions to help developers master Promise behavior.
Preface
The article uses code‑by‑code analysis to explore the complete registration and execution process of Promise microtasks, going beyond the usual surface‑level knowledge.
First code snippet
new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
}).then(() => {
console.log("外部第一个then");
return new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
}).then(() => {
console.log("内部第一个then");
}).then(() => {
console.log("内部第二个then");
});
}).then(() => {
console.log("外部第二个then");
});The output order is: 外部promise → 外部第一个then → 内部promise → 内部第一个then → 内部第二个then → 外部第二个then.
Second code snippet
new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
}).then(() => {
console.log("外部第一个then");
new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
}).then(() => {
console.log("内部第一个then");
}).then(() => {
console.log("内部第二个then");
});
}).then(() => {
console.log("外部第二个then");
});Because the outer return is omitted, the registration order changes, producing the output: 外部promise → 外部第一个then → 内部promise → 内部第一个then → 外部第二个then → 内部第二个then.
Third code snippet
new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
}).then(() => {
console.log("外部第一个then");
let p = new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
});
p.then(() => {
console.log("内部第一个then");
});
p.then(() => {
console.log("内部第二个then");
});
}).then(() => {
console.log("外部第二个then");
});Here the inner Promise is stored in a variable and its .then calls are registered synchronously, resulting in: 外部promise → 外部第一个then → 内部promise → 外部第二个then → 内部第一个then → 内部第二个then.
Fourth code snippet
let p = new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
});
p.then(() => {
console.log("外部第一个then");
new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
}).then(() => {
console.log("内部第一个then");
}).then(() => {
console.log("内部第二个then");
});
});
p.then(() => {
console.log("外部第二个then");
});The registration is non‑chained; both outer .then callbacks are queued after the inner Promise resolves, giving the order: 外部promise → 外部第一个then → 内部promise → 外部第二个then → 内部第一个then → 内部第二个then.
Core idea
Promise .then registration and execution are separate: registration follows the JavaScript call order (FIFO queue), while execution proceeds with synchronous code first, then microtasks, and finally macro‑tasks.
Promise/A+ vs WebKit implementation
The article compares a pure Promise/A+ library with the WebKit (Chrome/Safari) engine. It shows that adding return Promise.resolve() changes the microtask ordering in WebKit, causing extra .then callbacks to run earlier.
// Simplified Promise.resolve implementation from Promise/A+
Promise.resolve = function (value) {
if (value instanceof Promise) return value;
// ...type checks omitted for brevity...
if (typeof value === 'object' || typeof value === 'function') {
try {
var then = value.then;
if (typeof then === 'function') {
return new Promise(then.bind(value));
}
} catch (ex) {
return new Promise(function (resolve, reject) { reject(ex); });
}
}
return valuePromise(value);
};WebKit’s internal C++ resolver ultimately enqueues the resolved value as a microtask, which interacts differently with already‑registered outer .then callbacks.
Further examples illustrate how additional outer .then calls are affected by the return of Promise.resolve() in WebKit.
Conclusion
Understanding the separation between registration and execution of Promise .then callbacks is essential for predicting asynchronous flow, especially when dealing with different engine implementations.
References
[1]Promises/A+ : https://github.com/then/promise
WecTeam
WecTeam (维C团) is the front‑end technology team of JD.com’s Jingxi business unit, focusing on front‑end engineering, web performance optimization, mini‑program and app development, serverless, multi‑platform reuse, and visual building.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
