- Promise 是异步编程的底层容器,有三种状态,解决了“回调地狱”但链式调用依然冗长。
- async/await 是 Promise 的语法糖,让异步代码拥有同步的写法,极大地提高了代码的可读性和维护性,但在处理并行任务时仍需依赖
Promise.all等方法。
一、 Promise 有几种状态?
这是一个基础但必须回答精准的问题。Promise 对象代表一个异步操作,有三种状态:
- Pending(进行中) :初始状态,既没有被兑现,也没有被拒绝。
- Fulfilled(已成功) :意味着操作成功完成。
- Rejected(已失败) :意味着操作失败。
-
状态不可逆:状态一旦改变,就不会再变。
- 只能从
Pending变为Fulfilled。 - 或者从
Pending变为Rejected。 - 一旦变成
Fulfilled或Rejected,状态就凝固了,之后再调用resolve或reject都不会再有反应。
- 只能从
二、 async/await 和 Promise 有什么关系?
async/await 是 Promise 的语法糖(Syntactic Sugar)。它建立在 Promise 之上,是为了解决 Promise 的“链式调用”造成的代码可读性问题而生的。
具体关系可以从以下三个维度理解:
1. async 函数返回 Promise
async 关键字修饰的函数,无论内部返回什么值,它总是返回一个 Promise 对象。
- 如果返回一个普通值,Promise 状态变为
fulfilled,值为该值。 - 如果内部抛出异常,Promise 状态变为
rejected。
async function test() {
return 123; // 相当于 return Promise.resolve(123)
}
console.log(test() instanceof Promise); // true
test().then(res => console.log(res)); // 123
2. await 等待 Promise 解决
await 关键字后面通常跟一个 Promise 对象(如果不是,会被转成 resolve 的 Promise)。
它的作用是“暂停”函数执行,直到后面的 Promise 状态变为 fulfilled,然后拿到结果继续执行。如果 Promise 变为 rejected,则会抛出错误。
这就把“异步代码”写成了“同步风格”:
- Promise 写法(链式调用):
function getData() {
axios.get('/api/user')
.then(res => {
console.log(res);
return axios.get('/api/order'); // 链式调用,容易写成回调地狱
})
.then(res => {
console.log(res);
})
.catch(err => {
console.error(err);
});
}
- async/await 写法(同步风格):
async function getData() {
try {
const user = await axios.get('/api/user'); // 看起来像同步代码
console.log(user);
const order = await axios.get('/api/order');
console.log(order);
} catch (err) {
console.error(err); // 错误处理也更像同步的 try/catch
}
}
3. 错误处理的区别
- Promise 使用
.catch()方法捕获错误。 - async/await 通常配合
try...catch语句捕获错误。这让异步代码的错误处理逻辑与同步代码保持一致,代码结构更清晰。
注:1. async/await 并不能替代 Promise:await 必须等待 Promise 的结果,没有 Promise 就没有 await;- async/await 的写法容易让人忽略“并行”的场景。 如果两个请求没有依赖关系,用 await 写成顺序执行会浪费时间