async/await与Promise配合——从基础到进阶实战
前言
async/await
和 Promise
都是JS异步编程中重要部分,他们的关系是十分紧密。深入理解二者的关系是我们提高异步处理能力必须具备的,下面我将深入探究async/await
与Promise
的内在联系,揭示它们之间的关系和作用。
1. 语法糖和基础
- Promise 是ES6引入的一种解决异步问题的原生对象,它代表一个异步操作的结果,这个结果可能已经完成、正在进行,或者还未开始。Promise通过
.then()
、.catch()
、.finally()
等方法链式调用来处理异步操作的成功或失败结果。 - async/await 是ES8引入的基于Promise的更高层次的抽象,可以看作是Promise的语法糖。
async
关键字用于声明一个异步函数,而await
关键字用于等待一个Promise的结果,使得异步代码能够以更加同步的方式编写,提高了代码的可读性和简洁性。
下面两个目的一样的Promise链式调用示例和async/await示例:
Promise 示例
function fetchUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId === 1) {
resolve({ id: userId, name: "Alice" });
} else {
reject("User not found");
}
}, 1000);
});
}
fetchUserData(1)
.then(user => console.log(user))
.catch(err => console.error(err));
async/await 示例
async function fetchAndPrintUserData(userId) {
try {
const user = await fetchUserData(userId);
console.log(user);
} catch (err) {
console.error(err);
}
}
fetchAndPrintUserData(1);
2. 返回Promise
- async函数总是返回一个Promise。即使函数体没有显式返回任何值,它也会隐式返回一个resolved的Promise;如果函数体中有return语句,则返回的值会被包裹在一个resolved的Promise中;如果在函数体内抛出错误,则返回一个rejected的Promise。
async function returnPromiseExample() {
return "Hello, World!";
}
returnPromiseExample().then(result => console.log(result)); // 输出: Hello, World!
3. 异常处理
- 使用Promise时,需要通过
.catch()
来捕获异步操作中抛出的错误。 - 使用async/await,可以像处理同步代码中的错误一样,使用try/catch语句块来捕获异常,这使得错误处理更加直观和易于理解。
4. 等待Promise
- await 关键字只能在
async
函数内部使用,它会使代码暂停在该行,直到等待的Promise解析(resolve或reject),然后继续执行后续代码。这种方式避免了回调地狱,使得异步逻辑更像同步代码。
1.返回的Promise不做回应
async function AsyncOperation() {
return new Promise((resolve, reject)=>{
console.log('无resolve, reject回应')
})
}
async function awaitPromise() {
const res ='111'
const data = await someAsyncOperation();
console.log(res);
console.log(data);
}
我们可以看到await后面的res也未被打印出。
2.返回resolve
async function someAsyncOperation() {
return new Promise((resolve, reject)=>{
resolve('resolved')
})
}
async function waitForPromiseExample() {
const res ='111'
const data = await someAsyncOperation();
console.log(res);
console.log(data);
}
当await得到了一个已回复的Promise对象,那么await在返回之后直接执行后面的语句。
5. 流控制
- async/await 提供了更自然的流程控制机制,使得条件语句、循环等结构能更容易地应用于异步操作中,而不需要像使用Promise那样通过嵌套
.then()
来实现复杂的逻辑控制。
async function AsyncFunc1() {
await new Promise(resolve => setTimeout(resolve, 1000));
return "Result from AsyncFunc1";
}
async function AsyncFunc2() {
await new Promise(resolve => setTimeout(resolve, 1500));
return "Result from AsyncFunc2";
}
// 主异步函数,根据条件选择执行AsyncFunc1或AsyncFunc2
async function AsyncFunc() {
const condition = true; // 条件
let result;
if (condition) {
result = await AsyncFunc1();
} else {
result = await AsyncFunc2();
}
console.log(result);// 输出:Result from AsyncFunc1
}
AsyncFunc();
6. 兼容和互换性
- Promise 有更广泛的浏览器和环境支持,因为它是ES6的一部分,大多数现代浏览器和Node.js环境都支持。
- async/await 基于Promise构建,因此在支持async/await的环境中也可以直接使用Promise。同时,可以通过将Promise包装在async函数中,或者使用
.then()
和.catch()
来“转换”async/await风格的代码为Promise风格,保持良好的互操作性。
// Async/Await 版本
async function fetchDataAsync(id) {
const response = await fetch(`https://api.example.com/data/${id}`);
return response.json();
}
// Promise 版本
function fetchDataPromise(id) {
return fetch(`https://api.example.com/data/${id}`)
.then(response => response.json());
}
// 两者可互换使用
fetchDataAsync(1).then(data => console.log(data));
fetchDataPromise(1).then(data => console.log(data));
可以看到返回的两个请求是一模一样的。
总结
async/await
是基于Promise
设计的高级语法,旨在简化异步代码的编写,提供一种更为直观和易于阅读的编程模型。本质上,async/await
是对Promise
的封装和升级,允许以同步的方式编写异步逻辑,而实际上这些操作仍然是非阻塞的。
当使用async/await
时,开发者可以借助await
关键字等待Promise
的解决,使得代码在视觉上按照从上至下的顺序执行,无需链式.then()
回调。同时,通过在async
函数中使用标准的try...catch
语句,可以更自然地处理异步操作中可能发生的错误,这与在Promise
链中使用.catch()
方法相比,更加贴近同步编程的习惯。
转载自:https://juejin.cn/post/7388714402168389669