JavaScript异步编程核心是不阻塞主线程,回调函数易致“回调地狱”且错误难捕获,Promise通过状态管理、链式调用和统一错误处理提升可读性与组合能力。

JavaScript 的异步编程核心在于“不阻塞主线程”,回调函数和 Promise 都是实现方式,但设计思想、错误处理、可读性和组合能力差别明显。
回调函数:最基础的异步表达
回调函数是把一个函数作为参数传给另一个函数,在异步操作完成后被调用。比如 setTimeout 或老式 AJAX:
getUserById(123, function(user) {
console.log(user.name);
getPostsByUserId(user.id, function(posts) {
console.log(posts.length);
});
});
问题在于嵌套加深时容易形成“回调地狱”——逻辑难追踪、错误难捕获、流程难复用。每个回调都要手动检查 error 参数,且无法用 try/catch 捕获异步错误。
Promise:用状态管理替代嵌套调用
Promise 是一个对象,代表异步操作的最终完成(或失败)及其结果。它有三种状态:pending(进行中)、fulfilled(成功)、rejected(失败),且状态不可逆。
立即学习“Java免费学习笔记(深入)”;
- 用
.then()处理成功,.catch()统一捕获链上任意环节的错误 - 支持链式调用,避免深层嵌套:
fetch(...).then(res => res.json()).then(data => ...) - 天然兼容
try/catch(配合async/await) - 多个 Promise 可通过
Promise.all()、Promise.race()等组合控制并发行为
关键区别总结
-
错误处理:回调需在每个层级手动判断 error;Promise 错误会自动沿链向下传递,
.catch()可集中拦截 - 执行时机:Promise 构造器中的代码立即执行(microtask),而回调函数完全由调用方决定何时执行
-
可取消性:原生 Promise 不可取消;回调函数是否可取消取决于具体 API 设计(如
AbortController需额外配合) - 语义清晰度:Promise 明确表达了“未来某个值”,便于抽象和复用;回调更偏向过程式描述
实际建议
- 新项目优先使用
async/await(基于 Promise),写法接近同步,调试体验更好 - 封装老式回调 API 时,可用
Promise构造器包装,统一成 Promise 风格 - 避免混用:不要在
.then()中又写深层回调,破坏 Promise 链的优势 - 注意 Promise 的“静默失败”风险:没写
.catch()且未开启unhandledrejection监听时,错误会被忽略











