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

JS中async函数执行上下文工作原理:为何End先于Hello输出?

JavaScript await 与事件循环运行机制解析

问题背景

我正在学习JavaScript,遇到了一段JS代码片段,无法理解其运行逻辑。

代码如下:

let hello = () => Promise.resolve("Hello")

async function fun() {
  console.log("Inside")
  const result = await hello()
  console.log(result)
}

console.log("Start")
fun()
console.log("End")

控制台输出结果为:

Start
Inside
End
Hello

我不理解为何使用await关键字后,End仍会在Hello之前打印,希望了解该代码片段在事件循环中的运行机制,尤其是当fun()被推入调用栈时的具体过程。

执行过程详细拆解

JavaScript是单线程语言,同步任务在调用栈按顺序执行,异步任务会被放入任务队列,等调用栈清空后才会处理。这里的核心是await的工作逻辑,一步步拆解:

  • 第一步:执行最外层同步代码
    调用栈先执行console.log("Start"),控制台输出Start,执行完毕后调用栈清空。

  • 第二步:调用fun()并执行内部同步代码
    fun()被推入调用栈,先执行里面的同步语句console.log("Inside"),控制台输出Inside。
    接下来遇到await hello():

    1. 先执行hello(),返回一个已完成状态的Promise。
    2. await会暂停fun()的执行,把fun()从调用栈弹出,同时将await后面的代码(console.log(result))打包成回调函数,放到微任务队列里等待执行。
  • 第三步:继续执行剩余同步代码
    调用栈现在是空的,主线程继续执行最外层剩下的同步代码console.log("End"),控制台输出End,所有同步任务执行完毕,调用栈再次清空。

  • 第四步:处理微任务队列
    调用栈清空后,事件循环会优先处理微任务队列。找到之前await生成的回调函数,将其推入调用栈执行:
    回调函数拿到Promise的返回值"Hello",赋值给result,然后执行console.log(result),控制台输出Hello。

核心结论

await并不会阻塞整个主线程,它只是暂停当前async函数的执行,让主线程先把所有同步代码执行完毕,之后再回来处理await后续的逻辑。而Promise的回调属于微任务,会在所有同步任务完成后、下一轮事件循环启动前被处理,这就是为什么End会比Hello先打印。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 13:05:20