1. 什么是async/await
异步函数,也称为“async/await”( Promise 语法关键字),是 ES6 期约模式在 JS 函数中的应用。 async/await 是 ES8 规范新增的。这个特性从行为和语法上都增强了 JavaScript,让以同步方式写的代码能够异步执行。
以下是自己对 async/await 的基本概念理解与总结,不喜勿喷:
- async/await 本质上是一个语法糖,它是基于 Promise 的简化和封装
- await 可以理解成是 Promise 的 then 方法,只有执行 resolve 才会执行 then 方法
- 捕获 reject 建议使用 try/catch 来捕获 reject
- async 函数默认返回 Promsie 对象(被 Promise.resolve() 包装成期约对象),如果没有 return,则返回 undefined 的 Promise 对象
2. await
return返回值默认被包装成promsie对象,所以可以调用then方法
async function foo() {
return 3 // 会被包裹成Promise对象
}
foo().then(res => {console.log(res)}) // 输出3
async function bar() {
return await Promise.resolve('bar'); // await解析成'bar'字符串,经过async函数的return,'bar'又包裹成一个Promise对象
}
bar().then(console.log); // 所以这里才能执行then方法
3. 停止和恢复执行
- await 会等待后面的值封装成 Promise 对象在执行,即使 await 'bar' 是字符串也会把 'bar' 封装成 Promise 对象
- foo、bar、baz类似中文中的张三、李四
async function foo() {
console.log(await Promise.resolve('foo')); // 第二输出
}
async function bar() {
console.log(await 'bar'); // 第三输出
console.log('111') // 最四输出
}
async function baz() {
console.log('baz'); // 第一输出
}
foo();
bar();
baz();
4. try/catch 捕获错误
- async/await 不能直接捕获 Promise 抛出的错误;async/await 需结合 try/catch 来捕获 Promise 的错误, 如果不需要捕获错误则可以不使用 try/catch
- 以下3种分别区分使用 async/await 和不使用 async/await 处理捕获错误的不同方式
定义个公共Promise函数
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.5
if (success) {
resolve('Data fetched successfully')
} else {
reject('Failed to fetch data')
}
}, 1000)
})
}
- 使用 try/catch + async/await 来捕获错误
try {
const result = await fetchData();
console.log(result);
} catch (error) {
// 这里的catch可以直接捕获reject返回的内容
console.error('Error:', error);
}
- 不使用 async/await ,直接使用 Promise 链式调用来捕获错误
fetchData()
.then((result) => {
console.log(result);
})
.catch((error) => {
// 这里的catch捕获reject返回的内容
console.error('Error inside Promise chain:', error.message);
});
- 如下方式一的 catch 并不会捕获到错误,因为没有通过异步模式捕获错误(PS: 也可以理解为 try/catch 无法直接捕获 Promise 的错误,必须要配合 async/await 才可以捕获错误)
// 方式一
try {
new Promise((resolve, reject) => {
reject('fail1')
})
} catch(err) {
console.log('错误内容1: ', err) // 无法捕获 reject 错误
}
// 方式二
try {
await new Promise((resolve, reject) => {
reject('fail2')
})
} catch(err) {
console.log('错误内容: ', err) // 可以捕获 reject 错误
}
- try/catch 无法捕获直接由 setTimeout 异步执行的错误;try/catch 只能捕获同步代码中的错误
try {
setTimeout(() => {
throw new Error('Async error')
}, 1000);
} catch (error) {
console.error('错误:', error.message);
}