JavaScript异步编程核心是避免阻塞主线程并安全获取结果;回调易致嵌套、错误难捕获、并发难处理,现仅用于DOM事件等特定场景;应优先使用Promise与async/await。

JavaScript 异步编程不是“等代码跑完再干别的”,而是让耗时操作(比如网络请求、文件读取)不卡住主线程,同时提供机制来安全获取结果。回调函数是最早期的处理方式,但直接嵌套使用极易陷入 callback hell,现在只在特定场景(如 Node.js 原生 API、事件监听)中保留,不推荐作为主要异步控制手段。
为什么 callback 容易出问题
回调函数本身没有错,错在用法:一旦多个异步操作需要顺序执行或错误传递,就会出现多层缩进、错误处理分散、无法用 return 或 throw 统一控制流。
- 无法用
try...catch捕获异步回调里的错误 -
if (err) return callback(err)写三遍以上,逻辑就难维护 - 想并发发起 3 个请求并等全部完成?得手动计数,容易漏掉
callback调用 - Node.js 的
fs.readFile等老 API 仍用回调,但官方已同步提供fs.promises.readFile
现代替代方案:优先用 Promise + async/await
几乎所有浏览器和 Node.js(v8.0+)都原生支持 Promise,配合 async/await 可写出接近同步风格的异步代码,错误也能用 try...catch 统一处理。
async function fetchUserData() {
try {
const res = await fetch('/api/user');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
} catch (err) {
console.error('加载失败:', err.message);
}
}
-
await只能在async函数内使用 -
fetch返回的是Promise,不用手动包装new Promise - 链式调用用
.then()也行,但嵌套深了依然难读;await是线性写法 - 并发请求用
Promise.all([p1, p2, p3]),比手写计数器可靠得多
什么时候还必须写回调函数
不是所有地方都能立刻换成 Promise。以下情况绕不开回调:
立即学习“Java免费学习笔记(深入)”;
- DOM 事件绑定:
button.addEventListener('click', handler),handler就是回调 - 某些底层库(如 WebSocket 的
onmessage、onerror)只暴露回调接口 - Node.js 的
fs.watch、child_process.exec(非execSync)等流式 API - 需要兼容极老环境(IE),且不能引入 polyfill 时
这类回调建议只做最轻量的事:触发 Promise、转发事件、或调用封装好的异步函数,避免在里面塞业务逻辑。
真正难的不是语法,是判断“这个异步操作是否需要等待结果”——漏掉 await 或忘记处理 reject,程序不会报错,但行为会静默异常。别依赖“它看起来跑通了”。











