异步编程
回调函数
理解回调模式、回调地狱问题
回调函数
回调函数是 JavaScript 异步编程的基石,理解它才能掌握 Promise。
学完本章你将: 理解回调模式与回调地狱问题。
什么是回调?
回调就是把函数作为参数传递给另一个函数,等操作完成后调用。
javascript
// 同步回调
let nums = [1, 2, 3];
nums.forEach(function(n) {
console.log(n * 2);
});
// 异步回调
console.log("开始");
setTimeout(function() {
console.log("2秒后执行");
}, 2000);
console.log("结束");
// 输出:"开始" → "结束" → "2秒后执行"
回调传参约定
javascript
// Node.js 错误优先回调风格
function readFile(path, callback) {
// 模拟异步读取
setTimeout(() => {
if (path === "") {
callback(new Error("路径为空"), null);
} else {
callback(null, `文件内容:${path}`);
}
}, 1000);
}
readFile("data.txt", (err, data) => {
if (err) {
console.error("错误:", err.message);
return;
}
console.log(data);
});
回调地狱
javascript
// 多个异步操作按顺序执行时,回调嵌套越来越深
getUser(1, (err, user) => {
if (err) return console.error(err);
getPosts(user.id, (err, posts) => {
if (err) return console.error(err);
getComments(posts[0].id, (err, comments) => {
if (err) return console.error(err);
getLikes(comments[0].id, (err, likes) => {
if (err) return console.error(err);
console.log("最终结果:", likes);
// 越嵌套越深 → 回调地狱!
});
});
});
});
解决回调地狱
javascript
// 方式 1:命名函数
function step4(likes) { console.log(likes); }
function step3(err, comments) {
if (err) return;
getLikes(comments[0].id, step4);
}
function step2(err, posts) {
if (err) return;
getComments(posts[0].id, step3);
}
getUser(1, step2);
// 方式 2:Promise(下一章)
// 方式 3:async/await(再下一章)
回调的局限性
| 问题 | 说明 |
|---|---|
| 信任问题 | 回调可能被多次调用或不调用 |
| 流程控制 | 并发的回调不好控制顺序 |
| 错误处理 | try-catch 无法捕获异步回调的错误 |
javascript
// try-catch 无法捕获异步错误
try {
setTimeout(() => {
throw new Error("异步错误");
}, 1000);
} catch (e) {
console.log("捕获不到!"); // 不会执行
}