1. 回调地狱 (Callback Hell)
当需要执行多个连续的异步操作时,每个操作都依赖于前一个操作的结果,就会形成嵌套的回调结构,这就是回调地狱。
// 回调地狱示例
getUser(userId, function(user) {
getPosts(user.id, function(posts) {
getComments(posts[0].id, function(comments) {
getLikes(comments[0].id, function(likes) {
// 更多嵌套...
console.log(likes);
}, handleError);
}, handleError);
}, handleError);
}, handleError);
问题:代码可读性差、维护困难、错误处理繁琐。
2. Promise 与 Resolve/Reject
Promise 是 ES6 引入的解决回调地狱的方案,它有三种状态:
- pending (进行中)
- fulfilled (已成功) → 调用 resolve ()
- rejected (已失败) → 调用 reject ()
// 创建Promise对象
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true;
if (success) {
// 成功时调用resolve
resolve("操作成功");
} else {
// 失败时调用reject
reject(new Error("操作失败"));
}
}, 1000);
});
// 使用Promise
promise
.then(result => {
console.log(result); // 接收resolve的值
return "继续传递";
})
.then(nextResult => {
console.log(nextResult);
})
.catch(error => {
console.error(error); // 捕获reject的错误
})
.finally(() => {
console.log("无论成功失败都会执行");
});
Promise 通过链式调用解决了回调地狱的嵌套问题,但仍有大量的.then () 方法。
3. async/await
ES2017 引入的 async/await 是 Promise 的语法糖,让异步代码看起来像同步代码。
// 定义async函数
async function asyncOperation() {
try {
// 使用await等待Promise结果
const result1 = await promise1();
const result2 = await promise2(result1);
const result3 = await promise3(result2);
console.log(result3);
return result3;
} catch (error) {
// 捕获所有可能的错误
console.error(error);
} finally {
console.log("操作完成");
}
}
// 调用async函数(返回的仍是Promise)
asyncOperation().then(finalResult => {
console.log("最终结果:", finalResult);
});
4. 三级回调地狱的解决方案对比
原始回调地狱:
// 三级回调地狱
firstStep(function(result1) {
secondStep(result1, function(result2) {
thirdStep(result2, function(result3) {
console.log(result3);
}, handleError);
}, handleError);
}, handleError);
使用 Promise 解决:
// Promise链式调用解决
firstStep()
.then(result1 => secondStep(result1))
.then(result2 => thirdStep(result2))
.then(result3 => console.log(result3))
.catch(error => handleError(error));
使用 async/await 解决:
// async/await解决
async function solve() {
try {
const result1 = await firstStep();
const result2 = await secondStep(result1);
const result3 = await thirdStep(result2);
console.log(result3);
} catch (error) {
handleError(error);
}
}
solve();
5. 关键点总结
- Promise 通过.then () 链式调用解决回调嵌套问题
- resolve 用于将 Promise 状态改为成功并传递结果
- reject 用于将 Promise 状态改为失败并传递错误
- async 函数内部可以使用 await 关键字
- await 只能在 async 函数中使用,用于等待 Promise 完成
- async 函数返回的是一个 Promise 对象
- try/catch 可以捕获 await 过程中可能出现的错误
async/await 是目前最优雅的异步编程解决方案,它在 Promise 的基础上提供了更简洁、更易读的语法。