async函数是同步启动、异步收尾的语法糖,调用立即返回promise,await暂停执行流并注册微任务,错误传播严格遵循promise链规则。

async 函数不是“真正异步执行”的函数,而是一个同步启动、异步收尾的语法糖。它的生命周期横跨调用栈、微任务队列与 Promise 状态机,关键在于理解它如何把同步写法映射到底层异步调度机制中。
async 函数一调用就返回 Promise
无论函数体是否含 await,async 函数调用后立即返回一个 Promise 实例。这个 Promise 的初始状态是 pending,后续状态由函数内部逻辑决定:
- 若函数正常 return 非 Promise 值(如字符串、数字、对象),等价于 Promise.resolve(value),返回 fulfilled 状态的 Promise
- 若 return 一个已存在的 Promise,该 Promise 直接被透传,状态和结果不被二次包装
- 若函数中途 throw 错误,或 await 的 Promise 被 reject 且未被 try/catch 捕获,则返回 rejected 状态的 Promise
await 不阻塞线程,只暂停 async 函数执行流
await 关键字不会让 JavaScript 引擎“停住”整个线程,而是将当前 async 函数的剩余逻辑封装为一个微任务,在 await 后的 Promise settled(fulfilled 或 rejected)后排队执行:
- 遇到 await 表达式时,引擎会暂停当前 async 函数的执行上下文,并把后续代码(包括 return、throw、console.log 等)注册为该 Promise 的 then/catch 回调
- 这些回调属于微任务,会在当前宏任务结束、调用栈清空后,一次性全部执行完毕
- await 后面可以是任意值:若非 Promise,则自动包装为 Promise.resolve(x);若是 Promise,则直接等待其状态变更
async 函数体内的代码分段执行
async 函数体看似线性,实则被 await 切割成多个微任务片段。以如下代码为例:
async function foo() {console.log('1');
await Promise.resolve();
console.log('2');
return 'done';
}
执行顺序为:
- 调用 foo() → 输出 '1',然后 await 触发 Promise.resolve().then(() => { console.log('2'); return 'done'; })
- '1' 是同步输出;'2' 和最终 resolve 值在下一个微任务阶段执行
- 整个函数体的同步部分(到第一个 await 前)属于当前宏任务;后续部分属于微任务,不参与当前宏任务的连续执行
错误传播严格遵循 Promise 链规则
async 函数中的异常处理不是传统 try/catch 的简单延伸,而是与 Promise 的 rejection 流完全对齐:
- 未被 try/catch 包裹的 throw 或 await rejected Promise,会导致整个 async 函数返回的 Promise 进入 rejected 状态
- 即使在 catch 中 return 一个值,返回的仍是 Promise.resolve(value),而非普通值
- 错误不会“跳出”async 函数向上冒泡到外层同步代码,只能通过 .catch() 或 await 外层调用处的 try/catch 捕获
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











