为什么在外部触发多次调用时,async/await不能保证执行顺序?

前端开发 2026-07-10

我正在处理如下的异步函数:

async function doWork(id) {
  console.log("Start", id);
  await new Promise(res => setTimeout(res, 1000));
  console.log("End", id);
}

如果我按顺序调用它:

await doWork(1);
await doWork(2);

执行顺序是可预测的。

然而,如果同一个函数被外部触发(例如用户点击、事件或定时器):

doWork(1);
doWork(2);
doWork(3);

执行会变成交错执行:

Start 1
Start 2
Start 3
End 1
End 2
End 3

为什么会这样?

解决方案

这可能在Stack Overflow的某处已经有答案,因此下次值得快速搜索一下,但不管怎样,这是我的看法。

JavaScript被设计为非阻塞并发(单线程的异步执行)。如果它自动强制按顺序执行,就会阻塞执行。

async/await 不会让函数一个接一个地执行,除非你显式地 await 它们。所以当你这样做时:

doWork(1);
doWork(2);
doWork(3);

这意味着:

Start doWork(1)
Start doWork(2)
Start doWork(3)

它们都在同时运行。

且在这个函数内部:

async function doWork(id) {
  console.log("Start", id);
  await delay();
  console.log("End", id);
}

发生的情况是 "Start" 会立即执行,await 会暂停该函数,JS继续执行下一个调用,因此你会得到

Start 1
Start 2
Start 3

然后在1 秒后:

End 1
End 2
End 3

因此在某种意义上,await 并不意味着“在调用下一个函数之前等待”,而是意味着:“暂停这个函数,但让其他一切继续执行”。

要获得顺序,你要么显式地await

await doWork(1);
await doWork(2);
await doWork(3);

手动串联它:

doWork(1)
  .then(() => doWork(2))
  .then(() => doWork(3));

或者你也可以使用动态列表,比如:

[1,2,3].reduce(
  (p, id) => p.then(() => doWork(id)),
  Promise.resolve()
);
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章