JavaScript异步处理应依场景选择:回调适用于简单链式调用,Promise统一状态与错误传播,async/await是其语法糖,降低嵌套负担;三者常混用,需注意错误边界。

JavaScript 异步处理不是选哪个“更高级”,而是看场景和协作成本:回调适合简单链式调用,Promise 是错误处理和组合的分水岭,async/await 本质是 Promise 语法糖,但大幅降低嵌套和 .then() 的心智负担。
回调函数为什么容易出问题
回调本身没有错,错在多层嵌套 + 错误分散时难以维护。典型现象是“回调地狱”(callback hell):缩进越来越深、错误处理重复、无法用 return 或 try/catch 统一捕获。
- 异步操作之间无原生顺序保障,靠手动传参或闭包维持上下文,易出
undefined或变量覆盖 -
setTimeout、fs.readFile(Node.js)这类 API 的回调参数顺序不统一(如 Node 回调是(err, data),而浏览器addEventListener没有err) - 无法用
for...of或map直接处理多个异步任务,必须手写循环+计数器
Promise 解决了什么,又带来什么约束
Promise 把“异步结果”变成可传递、可组合的一等公民,核心价值不在写法,而在统一了状态(pending/fulfilled/rejected)和错误传播路径。
- 构造时必须传入执行器函数,且只能 resolve/reject 一次 —— 避免回调多次触发导致状态混乱
-
.then()和.catch()总是异步执行(微任务),与同步代码严格分离,避免竞态 - 链式调用中,任意
.then()返回非Promise值会自动包装,返回Promise则等待其完成 —— 这是组合多个异步操作的基础 - 注意:
Promise.all()遇到任一拒绝就短路,需用Promise.allSettled()获取全部结果
async/await 不是新机制,而是 Promise 的语法封装
async 函数返回值一定是 Promise,await 只是暂停当前函数执行,等右侧表达式(必须是 Promise 或 thenable)完成后再继续 —— 它不能脱离 Promise 生态单独工作。
立即学习“Java免费学习笔记(深入)”;
- 必须在
async函数内使用await,否则报SyntaxError: await is only valid in async function -
await后面如果不是Promise,会自动转成Promise.resolve(value),所以await 123是合法的 - 错误必须用
try/catch捕获,catch块能拿到被 reject 的值,但不会自动吞掉错误 —— 这点比回调更可控 - 并行执行多个异步操作时,别写成
await a(); await b();(串行),应先const [aRes, bRes] = await Promise.all([a(), b()])
实际项目中怎么选
没有银弹。现代代码里混用很常见:库内部可能暴露 Promise,上层用 async/await 消费;遗留回调 API(如某些 WebSocket 库)则用 new Promise() 包一层再 await。
- 新业务逻辑优先写
async/await,尤其涉及条件分支、循环或错误恢复时 - 需要同时监听多个异步源(如
Promise.race()实现超时)、或做复杂组合(Promise.allSettled()+ 过滤)时,直接操作Promise更清晰 - 回调未完全淘汰:事件监听(
addEventListener)、Node.js 流(stream.on('data', ...))仍是回调驱动,强行 Promise 化反而增加开销
最容易被忽略的是错误边界 —— async/await 中漏写 try/catch,或 Promise 链末尾没加 .catch(),都会让错误静默失败,尤其在生产环境难以定位。











