Z
ZHANK
异步编程

回调函数

理解回调模式、回调地狱问题

回调函数

回调函数是 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("捕获不到!"); // 不会执行
}