JavaScript中Promise的执行顺序举例详析

 更新时间:2025年05月09日 10:10:33   作者:mosen868  
这篇文章主要介绍了JavaScript中Promise执行顺序的相关资料,通过示例代码分析,展示了同步任务、微任务和宏任务的执行顺序,并解释了为什么第一个then返回Promise时,输出顺序会发生变化,文中介绍的非常详细,需要的朋友可以参考下

概述

理解 Promise 的执行顺序时,需要牢记以下两点:

  • 微任务与宏任务的优先级

    • 微任务:Promise.then()catchfinally 是微任务。
    • 宏任务:setTimeoutsetInterval 是宏任务。
    • 微任务的优先级高于宏任务:在一次事件循环中,先清空所有的微任务队列,再执行下一个宏任务。
  • Promise 是基于微任务实现的

    • 当一个 Promise 的状态变为 resolved 或 rejected 时,它的 .then() 回调会被加入微任务队列,等待当前任务(包括微任务)完成后执行。

示例代码分析

代码分析

以下代码可以帮助理解 Promise 和 setTimeout 的执行顺序:

console.log("script start");

setTimeout(() => {
  console.log("setTimeout 1");
}, 0);

Promise.resolve()
  .then(() => {
    console.log("promise 1");
    return Promise.resolve().then(() => {
      console.log("promise 2");
    });
  })
  .then(() => {
    console.log("promise 3");
  });

setTimeout(() => {
  console.log("setTimeout 2");
}, 0);

console.log("script end");

执行过程解析

  • 同步任务:立即执行

    • console.log("script start") 输出 "script start".
    • setTimeout 的两个回调函数被放入 宏任务队列,等待事件循环调度。
    • Promise.resolve() 被调用,then() 的回调被放入 微任务队列

    输出结果:

  • script start
    script end

  • 主线程执行完同步任务后,开始执行微任务队列

    • 微任务队列的顺序如下:
      • 第一个 .then() 输出 "promise 1" 并返回一个新的 Promise
      • 新的 Promise.then() 输出 "promise 2"
      • 第二个 .then() 输出 "promise 3"

    输出结果:

    promise 1
    promise 2
    promise 3
    
  • 清空微任务队列后,开始执行宏任务队列

    • 宏任务队列的两个 setTimeout 回调依次执行,输出 "setTimeout 1" 和 "setTimeout 2"

    输出结果:

    setTimeout 1
    setTimeout 2
    

最终输出

综合以上,代码的输出顺序为:

script start
script end
promise 1
promise 2
promise 3
setTimeout 1
setTimeout 2

总结

  • 同步任务优先执行,输出 script start 和 script end
  • 微任务队列优先于宏任务队列。
  • Promise.then() 的回调会依次进入微任务队列。
  • setTimeout 的回调进入宏任务队列,最后执行。

(拓展)问题补充

如果第一个then不是返回return promise,而是直接执行一个Promise.resolve().then(() => { console.log("promise 2"); });结果是不是
会变成 promise 1 → promise 3 → promise 2。结果是的。

为什么会这样?

当 Promise.resolve().then() 不通过 return 将内部的 Promise 链接到外部 then 时,promise 2 的执行不再是当前链的一部分,它会被单独添加到 微任务队列的末尾,导致执行顺序的变化。

示例代码

以下是修改后的代码:

console.log("script start");

Promise.resolve()
  .then(() => {
    console.log("promise 1");
    Promise.resolve().then(() => {
      console.log("promise 2");
    });
  })
  .then(() => {
    console.log("promise 3");
  });

console.log("script end");

执行过程解析

  • 同步任务

    • 输出 "script start"
    • 主线程继续,将第一个 Promise.then() 的回调加入 微任务队列
    • 输出 "script end"

    当前输出:

    script start
    script end
    
  • 微任务队列开始执行

    • 执行第一个 .then(),输出 "promise 1"
      在此回调中,一个新的微任务promise 2 的回调)被加入 微任务队列末尾
    • 执行第二个 .then() 的回调,输出 "promise 3"

    当前输出:

    promise 1
    promise 3
    
  • 微任务队列剩余任务

    • 微任务队列中剩余的任务是 promise 2 的回调,输出 "promise 2"

    最终输出:

    promise 2
    

总输出结果

综合以上,完整的输出顺序是:

script start
script end
promise 1
promise 3
promise 2

关键点解析

  • 链式调用和微任务队列当你不通过 return 将一个新的 Promise 链接到当前 then,它的回调会独立加入 微任务队列的末尾,而不是成为当前链的一部分。

  • 对比:返回 Promise如果 return Promise.resolve().then(...),那么 promise 2 的执行会成为当前链的一部分,顺序为 promise 1 → promise 2 → promise 3

改变的核心代码

  • 独立的微任务:

    Promise.resolve().then(() => {
      console.log("promise 2");
    });
    
  • 作为链的一部分:

    return Promise.resolve().then(() => {
      console.log("promise 2");
    });
    

两种写法的区别在于是否将新的 Promise 加入当前链。

总结

到此这篇关于JavaScript中Promise的执行顺序举例详析的文章就介绍到这了,更多相关JS Promise执行顺序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论