JavaScript中Promise的then/catch/finally推入微任务队列的顺序探究
JavaScript中Promise处理函数(then/catch/finally)的微任务队列推入逻辑
测试案例与疑问
Case 1
new Promise((resolve, reject) => { resolve(1); }) .then((result) => console.log(result)) .catch((error) => console.log(error)) new Promise((resolve, reject) => { reject('Error!'); }) .then((result) => console.log(result)) .catch((error) => console.log(error)) new Promise((resolve, reject) => { resolve(3); }) .then((result) => console.log(result)) .catch((error) => console.log(error))
- 预期结果:1 - Error! - 3
- 实际结果:1 - 3 - Error!
推测:Promise处理函数推入MicroTask队列时存在优先级:.then() > .catch()
Case 2.1
new Promise((resolve, reject) => { resolve(1); }) .finally(() => console.log('Promise settled! 1')) .then((result) => console.log(result)) .catch((error) => console.log(error)) new Promise((resolve, reject) => { reject('Error!'); }) .then((result) => console.log(result)) .catch((error) => console.log(error)) .finally(() => console.log('Promise settled! 2')) new Promise((resolve, reject) => { resolve(3); }) .then((result) => console.log(result)) .catch((error) => console.log(error)) .finally(() => console.log('Promise settled! 3'))
- 预期结果:Promise settled! 1 - Error! - 3 - 1 - Promise settled! 2 - Promise settled! 3
- 实际结果:Promise settled! 1 - 3 - Error! - Promise settled! 2 - Promise settled! 3 - 1
推测:Promise处理函数推入MicroTask队列时存在优先级:.finally() > .then() > .catch()
Case 2.2
new Promise((resolve, reject) => { resolve(1); }) .finally(() => console.log('Promise settled! 1')) .then((result) => console.log(result)) .catch((error) => console.log(error)) new Promise((resolve, reject) => { reject('Error! 2'); }) .finally(() => console.log('Promise settled! 2')) .then((result) => console.log(result)) .catch((error) => console.log(error)) new Promise((resolve, reject) => { reject('Error! 3'); }) .then((result) => console.log(result)) .catch((error) => console.log(error)) .finally(() => console.log('Promise settled! 3')) new Promise((resolve, reject) => { resolve(4); }) .then((result) => console.log(result)) .catch((error) => console.log(error)) .finally(() => console.log('Promise settled! 4'))
- 预期结果:Promise settled! 1 - Promise settled! 2 - Error! 3 - 4 - 1 - Error! 2 - Promise settled! 3 - Promise settled! 4
- 实际结果:Promise settled! 1 - Promise settled! 2 - 4 - Error! 3 - Promise settled! 3 - Promise settled! 4 - 1 - Error! 2
推测:Promise处理函数推入MicroTask队列时存在优先级:.finally() > .then() > .catch()
原理讲解:你的推测并不正确
Promise的then/catch/finally本身没有优先级之分,它们的执行顺序由Promise状态变更时机和链式调用的依赖关系共同决定,核心逻辑如下:
1. 状态匹配与微任务触发
当Promise从pending变为resolved/rejected时,只有与状态匹配的回调才会被包装成微任务推入队列:
then的第一个回调仅在Promise resolved时触发;catch的回调仅在Promise rejected时触发;finally的回调无论Promise是resolved还是rejected,只要状态变更(settled)就会触发。
2. 链式调用的依赖逻辑
then/catch/finally都会返回新的Promise,新Promise的状态依赖于前一个回调的执行结果:
finally执行完成后,新Promise会完全继承原Promise的状态和值,后续的then/catch回调需等待finally执行完毕才会触发;- 若原Promise rejected,
then的resolve回调不会执行,其返回的新Promise会继承rejected状态,后续的catch回调需等待这个新Promise状态确认后才会被推入队列。
3. 测试案例的具体解析
- Case 1:三个Promise同步执行,第一个和第三个直接resolved,它们的
then回调会立即被推入微任务队列;第二个Promise rejected,其then的resolve回调不匹配状态,返回的新Promise变为rejected,直到这个新Promise状态确认后,catch回调才会被推入队列。因此队列顺序是:第一个then→ 第三个then→ 第二个catch,执行结果为1-3-Error!。 - Case 2.1:第一个Promise的
finally回调因状态settled先被推入队列,执行完成后,其返回的新Promise继承resolved状态,后续的then回调才会被推入队列;第三个Promise的then回调直接在原Promise resolved时被推入队列,因此会先于第一个Promise的then执行;第二个Promise的catch回调需等待其then返回的rejected Promise确认状态后才会被推入队列,所以在第三个then之后执行。
核心结论
- 微任务队列遵循先进先出原则,
then/catch/finally本身无优先级; - 回调是否被推入队列,取决于对应的Promise状态是否匹配;
- 链式调用中,后续回调的触发依赖于前一个回调的执行完成,形成嵌套的微任务触发逻辑。
内容的提问来源于stack exchange,提问作者together learning
相关产品推荐
相关产品推荐

