Promise 实现异步流程控制
🎯 引言
通过这篇文章,你将了解前端异步编程的基础——Promise,掌握如何用 .then()、.catch()、.finally() 处理异步操作,理解 Promise 链式调用的优势以及回调地狱的问题。更重要的是,你会学会使用 async/await,让你的异步代码更简洁、易读、更符合直觉,从而提升代码质量和开发效率。
🌀 Promise 是什么?
简单来说,Promise 就像是你做某件事情的“承诺”。它代表一个未来可能完成或者失败的操作结果。你可以把它想象成一个“盒子”,这个盒子里装着异步操作的结果,可能是成功的值,也可能是失败的原因。
Promise 有三种状态:
等待中(pending):还没完成或失败,正在进行中
已完成(fulfilled):操作成功完成,有了结果
已失败(rejected):操作失败,出错了
✨ Promise 基本用法
创建一个 Promise 非常简单。你需要传入一个函数,这个函数里有两个参数:resolve 和 reject。执行异步操作后,你调用 resolve 表示成功,调用 reject 表示失败。
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true; // 模拟操作结果
if (success) {
resolve('操作成功!');
} else {
reject('操作失败!');
}
}, 1000);
});
上面代码表示:等待 1 秒后,告诉 Promise 结果是成功还是失败。
⚡️ .then()、.catch()、.finally() 怎么用?
.then():当 Promise 成功时执行,接收成功的结果。.catch():当 Promise 失败时执行,接收失败的原因。.finally():不管成功还是失败,都会执行,可以用来做收尾工作,比如关闭加载动画。
myPromise
.then(result => {
console.log('成功回调:', result);
})
.catch(error => {
console.error('失败回调:', error);
})
.finally(() => {
console.log('无论成功失败都会执行');
});
🔗 Promise 链式调用
Promise 的强大之处还在于它支持链式调用。你可以把多个异步操作一个接一个地写出来,不用陷入回调层层嵌套。
new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 500); // 第一步,返回数字 1
})
.then(result => {
console.log(result); // 1
return result * 2;
})
.then(result => {
console.log(result); // 2
return result * 3;
})
.then(result => {
console.log(result); // 6
});
链式调用的神奇之处在于:
- 每个
.then都会返回一个新的 Promise,允许后续继续操作 - 传递的结果会自动成为下一个
.then的输入
⚠️ 回调地狱的问题
在 Promise 出现之前,异步操作常用回调函数实现,但很容易陷入“回调地狱”,代码非常难读,维护也不方便。
示例:
getData(function (a) {
getMoreData(a, function (b) {
getEvenMoreData(b, function (c) {
// 一层层嵌套,代码越来越深
});
});
});
当异步操作过多时,代码像金字塔一样往里缩,难以理解和维护。
Promise 通过链式调用,解决了回调地狱的问题,但链式写法有时候仍然不够直观。
🚀 什么是 async/await?解决了什么问题?
async / await 是 ES2017 引入的语法糖,基于 Promise,它让异步代码看起来像同步代码,更加简洁直观。
你可以用 await 关键字“等待”一个 Promise 完成,然后拿到结果,无需写 .then()。
举个例子:
async function fetchData() {
const result = await myPromise; // 等待 Promise 完成
console.log(result);
}
await 时候,记得检查函数前面是否添加 async,否则会报错哦!这样写最大的好处是:
- 代码更平铺直叙,逻辑清晰
- 错误处理用
try...catch,结构更规范 - 减少了回调和链式调用的复杂度
🛠 async/await 如何使用?
使用 async/await 主要步骤:
- 在函数前加
async,表示这个函数是异步函数,返回一个 Promise。 - 在异步操作前加
await,暂停执行,等待操作完成。 - 用
try...catch捕获异常,处理失败情况。
示例:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function doTasks() {
try {
console.log('开始任务');
await delay(1000); // 等待 1 秒
console.log('任务 1 完成');
await delay(1000);
console.log('任务 2 完成');
return '全部任务完成';
} catch (error) {
console.error('任务失败:', error);
}
}
doTasks().then(result => console.log(result));
这里我们用 delay 模拟异步等待,代码顺序执行,阅读体验像写同步代码一样。
Promise.all 并发执行,提高性能。示例:
async function fetchAll() {
const [a, b] = await Promise.all([fetchA(), fetchB()]);
}
🧾 小节总结
- Promise 是异步编程的基础,代表一个未来的操作结果,有三种状态。
.then(),.catch(),.finally()是 Promise 的常用处理方法,支持链式调用,解决了回调地狱部分问题。- async/await 是语法糖,让异步代码更像同步代码,写起来更方便、易读。
❓ 知识问答(Q&A)
Q:Promise 的三种状态分别是什么?
A:等待中(pending)、已完成(fulfilled)、已失败(rejected)。
Q:async/await 是什么?为什么用它?
A:async/await 是基于 Promise 的语法糖,能让异步代码像同步代码一样写,提高代码可读性和维护性。
Q:如何捕获 async 函数中可能出现的错误?
A:使用 try...catch 块包裹 await 的代码,捕获异常。
🧪 小练习
- 请写一个函数,返回一个 Promise,延迟 2 秒后返回“成功”。用
.then打印结果。
function delaySuccess() {
// 你的代码在这里
}
delaySuccess().then(result => console.log(result));
- 用 async/await 重写上面的函数,使用 try/catch 捕获错误。
async function asyncDelaySuccess() {
// 你的代码在这里
}
asyncDelaySuccess();
🎉 恭喜你已经掌握 Promise、链式调用、async/await 异步编程技能啦! 继续练习,前端异步编程不再难!
