背景
要理解 NewPromiseResolveThenableJobTask 这个微任务的作用,需要先回到它的创建场景 :当一个 Promise 的 then 回调(或其他 Promise 相关回调)返回了一个 可 thenable 对象 (通常是另一个 Promise,但也包括自定义的、有 then 方法的对象)时,JS 引擎会创建这个微任务,本质是为了 确保 "返回的 thenable 对象" 的状态完全确定后,再继续执行后续的 Promise 链。
如下代码,后续讨论依托于此段代码展开:
js
Promise.resolve()
.then(() => {
console.log(0);
return Promise.resolve(4);
})
.then((res) => {
console.log(res);
});
先明确前提:为什么需要这个微任务?
Promise 链的核心规则是 "后续的 then 回调,必须等待前一个 then 回调的 "返回值" 状态确定后才执行 "。如果前一个 then 回调返回的是一个普通值(比如 4、'a'),那很简单:直接把这个普通值作为下一个 Promise 的 "成功值",立刻触发下一个 then 的微任务。
但如果返回的是一个Promise(或可 thenable 对象) (比如代码中 return Promise.resolve(4)),情况就复杂了:这个返回的 Promise 本身是 "异步状态"(即使是 Promise.resolve(4) 这种 "立即成功" 的,也不是同步执行),必须等待它的 then 回调执行完(状态完全确定),才能把它的结果传给下一个 then。
这时候,NewPromiseResolveThenableJobTask 就是用来干这个 "等待并传递结果" 的活的。
NewPromiseResolveThenableJobTask 微任务具体做什么?
它的执行逻辑可以拆解为 3 个核心步骤,本质是 "代理执行返回的 thenable 对象的 then 方法,并把结果同步给当前 Promise 链":
1. 先明确这个微任务的 "3 个输入参数"
在创建这个微任务时,引擎会传入 3 个关键信息(对应 ECMA 规范的定义: #sec-newpromiserelovethenablejobtask):
promiseToResolve:当前 Promise 链中的 "中间 Promise"(即前一个then执行后返回的新 Promise,后续的then都是挂在这个 Promise 上的)。thenable:前一个then回调返回的 "可 thenable 对象"(比如代码中return Promise.resolve(4)里的这个 Promise)。then:thenable对象自身的then方法(比如 Promise 原型上的Promise.prototype.then)。
js
const promiseToResolve = Promise.resolve().then(() => {
return [[thenable 对象]]: {
[[then 方法]]: (onFulfilled, onRejected) => {}
}
})
2. 微任务执行的核心逻辑
当这个微任务被执行时,会干两件关键的事:
第一步:调用 thenable 的 then 方法,绑定 "结果传递回调"
微任务会主动调用 thenable.then(...),并传入两个回调函数(相当于 "代理回调"):
- 成功回调(
onFulfilled):如果thenable成功(比如Promise.resolve(4)成功),就会触发这个回调,把thenable的成功值(比如 4)传给promiseToResolve,让promiseToResolve也变成 "成功状态",并把 4 作为它的成功值。 - 失败回调(
onRejected):如果thenable失败(比如Promise.reject(5)),就会触发这个回调,把thenable的失败原因传给promiseToResolve,让promiseToResolve变成 "失败状态"。
第二步:触发后续的 Promise 链
一旦 promiseToResolve 的状态被确定(成功 / 失败),引擎就会为 promiseToResolve 上挂载的后续 then 回调(比如代码中第二个 then((res) => console.log(res)))创建新的微任务,把刚才传递过来的结果(比如 4)传给这个后续回调,让 Promise 链继续执行。
结合代码,看这个微任务的具体作用
javascript
Promise.resolve() // 1. 初始 Promise(成功状态,值为 undefined)
.then(() => { // 2. 第一个 then 回调(cb1)
console.log(0); // 3. 同步打印 0
return Promise.resolve(4); // 4. 返回一个新的 Promise(记为 P4)
})
.then((res) => { // 5. 第二个 then 回调(cb2,挂在 "中间 Promise":P_mid 上)
console.log(res); // 6. 最终打印 4
});
这里 NewPromiseResolveThenableJobTask 的执行过程完全贴合上面的逻辑:
-
执行
cb1时,返回了Promise.resolve(4)(即thenable = P4),引擎创建NewPromiseResolveThenableJobTask微任务,传入:promiseToResolve = P_mid(第一个 then 返回的中间 Promise,cb2 挂在它上面)thenable = P4then = P4.then(即 Promise 原型的 then 方法)。
-
当这个微任务执行时:
- 调用
P4.then(成功回调, 失败回调):因为P4是Promise.resolve(4)(已成功),触发PromiseResolveThenableJobTask的执行流程(重点)。 - "成功回调" 把
4传给P_mid,让P_mid变成 "成功状态",值为 4。 - 引擎为
P_mid上的cb2创建新微任务,后续执行这个微任务时,就会把4传给cb2,打印出4。
- 调用
重点核心(PromiseResolveThenableJobTask被执行):
PromiseResolveThenableJobTask 的被执行过程,esma 规范 的描述

其实它规定了这个 PromiseResolveThenableJobTask 要作为异步任务去执行(加入任务队列);
和 v8::builtins::promise-resolve.tq 的处理是一样的。v8 把 它加入了 微任务队列
但是,这个任务后续的被执行,就没有说了,规范上我并没有找到;
但是,看了 PromiseResolveThenableJobTask 的 v8 具体实现, 它分了两种情况来处理的:
thenable对象是Promise对象时;执行 PerformPromiseThen的实现方式;- 如果 promise 是
pendding态,会创建一个NewPromiseReaction任务, 等待 promise 兑现; - 如果 promise 是
fulfiled|rejected, 则会创建一个微任务,加入到微任务队列,等待执行;
- 如果 promise 是
thenable对象是非Promise 对象时;直接走 resolve function 逻辑;- 直接调用 resolve(结果),兑现 promise;
如图(PromiseResolveThenableJob):


也就是说,以下两段代码输出的结果是不一样的:
js
Promise.resolve()
.then(() => {
console.log(0);
return Promise.resolve(4);
})
.then((res) => {
console.log(res);
});
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(5);
});
// 输出:0,1,2,3,4,5
js
Promise.resolve()
.then(() => {
console.log(0);
return {
then(onFulfilled, onRejected) {
onFulfilled(4);
},
};
})
.then((res) => {
console.log(res);
});
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(5);
});
// 输出:0,1,2,4,3,5
一句话总结
NewPromiseResolveThenableJobTask 就是一个 "结果传递代理微任务":专门处理 "then 回调返回 thenable 对象" 的场景,确保这个 thenable 对象的状态确定后,把它的结果同步给当前 Promise 链的中间 Promise,再触发后续的 then 回调,保证 Promise 链的顺序和状态正确性。
注意的点是:
thenable对象是 Promise对象 和 普通包含实现 then 方法的对象,PromiseResolveThenableJobTask 的处理方式是不一样的;