You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript同步异步代码执行顺序疑问:日志顺序解析

JavaScript事件循环与Promise执行顺序答疑

以下是一段TypeScript代码及其执行日志,针对输出顺序的疑问逐一解答:

代码示例

console.log("-------------------------- (LOG 1)");

setTimeout(() => console.log("-----------------------------(LOG 2)"), 1000);

const fetchedData = fetch("https://pokeapi.co/api/v2/pokemon/ditto");

const fnReturningNewPromise = () => {
  return new Promise<string>((resolve, reject) => {
    if (1 == 1) {
      console.log("LOG 3 - new Promise in return Statement");
      resolve("fnReturningNewPromise - resolved");
    }

    reject("fnReturningNewPromise - rejected");
  });
};

const customPromise = new Promise<string>((resolve, reject) => {
  if (1 === 1) {
    console.log("LOG 4 - new Promise");
    resolve("Promise resolved");
  } else {
    reject("REJECTED");
  }
});

fetchedData
  .then((res) => {
    console.log("LOG 5 - fetchedData 1st then - res.json()");
    return res.json();
  })
  .then((data) => console.log("LOG 6 - with fetching"));

Promise.resolve(1).then((res) =>
  console.log("LOG 7 - immidielty resolved", res)
);

customPromise
  .then((response) => response)
  .then((data) => console.log("LOG 8 - without fetching"));

console.log("LOG 9 - sync code");

setTimeout(() => {
  console.log("LOG 10 - setTimeout - immidietly resolved");
}, 0);

fnReturningNewPromise().then((res) =>
  console.log("LOG 11 - resolving promise returned from fn: ", res)
);

执行日志

-------------------------- (LOG 1) 
LOG 4 - new Promise 
LOG 9 - sync code 
LOG 3 - new Promise in return Statement 
LOG 7 - immidielty resolved 1
LOG 11 - resolving promise returned from fn:  fnReturningNewPromise - resolved 
LOG 8 - without fetching 
LOG 10 - setTimeout - immidietly resolved 
LOG 5 - fetchedData 1st then - res.json() 
LOG 6 - with fetching 
-----------------------------(LOG 2)

疑问解答

1. 纯同步代码LOG 9为何在LOG 4之后输出?

new Promise()的执行器函数(即传入的(resolve, reject) => {...})是同步执行的。代码执行到const customPromise = new Promise(...)时,会立刻调用执行器函数,里面的console.log("LOG 4 - new Promise")属于同步代码,直接输出。而console.log("LOG 9 - sync code")写在customPromise定义之后,因此LOG 4先输出,LOG 9后输出。

2. 既然LOG 4是Promise构造函数内的同步代码,为何函数返回的Promise内的LOG 3未在LOG 4之前输出?

fnReturningNewPromise是一个函数,只有主动调用它时,内部的new Promise()才会执行。代码中fnReturningNewPromise()的调用在console.log("LOG 9 - sync code")之后,所以它内部的LOG 3自然在LOG 4之后输出——LOG 4是定义customPromise时同步执行的,而LOG 3要等到函数被调用才会触发。

3. LOG7、LOG11、LOG8的顺序为LOG7→LOG11→LOG8,为何关联LOG4的LOG8晚于关联LOG3的LOG11?

微任务队列按添加顺序执行,拆解顺序如下:

  1. 执行Promise.resolve(1).then(...)时,对应的回调被加入微任务队列,这是第一个微任务(对应LOG7)。
  2. 执行customPromise.then(...).then(...)时,第一个then(response => response)被加入微任务队列(第二个微任务);只有当这个微任务执行完毕,返回的resolved Promise的第二个then(对应LOG8)才会被加入微任务队列。
  3. 调用fnReturningNewPromise()时,同步输出LOG3,随后这个Promise立刻resolve,它的then回调(对应LOG11)被加入微任务队列(第三个微任务)。

同步代码执行完毕后,微任务队列的顺序为:LOG7的回调 → LOG11的回调 → LOG8的回调。因此执行顺序是LOG7→LOG11→LOG8。

4. setTimeout属于宏任务,优先级低于Promise微任务,为何LOG10未在最后(LOG2之前)输出?

宏任务队列同样按添加顺序执行:

  1. 第一个setTimeout(1000ms延迟)先被加入宏任务队列。
  2. 第二个setTimeout(0ms延迟)后被加入宏任务队列。

当所有微任务执行完毕后,事件循环会处理宏任务队列,先执行0ms延迟的setTimeout(LOG10),再等待1000ms后执行第一个setTimeout(LOG2)。而fetch的回调(LOG5、LOG6)需要等待网络请求完成后才会加入微任务队列,它的触发晚于0ms的setTimeout——因为网络请求需要耗时,在LOG10触发时,fetch的响应还未返回,因此LOG10会在LOG5、LOG6之前输出,等fetch响应返回后才会执行其then回调。


内容的提问来源于stack exchange,提问作者TheCodemate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 01:57:51