ES8 引入了 async 异步函数,它是 Generator 生成器函数的语法糖。
async 异步函数对 Generator 生成器函数的改进,体现在以下四点:
- 内置执行器:Generator 生成器函数的执行必须依靠执行器,所以才有了 next 方法;而 async 函数自带执行器。也就是说,async 函数的执行与普通函数一模一样,不再需要手动调用 next 方法。
- 更好的语义:async 和 await,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。
- 更广的适用性:async 函数的 awati 命令后面,可以是 Promise 函数和原始类型的值。
- 返回值是 Promise:async 函数的返回值是 Promise,这比 Generator 函数的返回值是 Iterator 对象方便多了,可以用 then 指定下一步的操作。进一步说,async 函数完成可以看作是多个异步操作,包装成的一个 Promise 对象,而 await 命令就是内部 then 命令的语法糖。
// 普通函数
function fn() {}
// 生成器函数
function* fn() {}
// async 异步函数
async function fn() {}
const fn = async function() {}
const fn = async() => {}
async 异步函数内部代码的默认执行过程和普通函数是一样的。默认情况下也是同步执行。
async function fn() {
console.log(1)
console.log(2)
}
fn()
async 异步函数的返回值:
async 异步函数的返回值是一个 Promise 对象。
- 如果没有返回值,默认返回
Promise.resolve(undefined)
,那么 async 异步函数返回值的状态是 fulfilled。 - 如果返回值是一个普通值(非 Promise 类型,且不是 thenable 对象),返回值会被包裹到
Promise.resolve()
中,那么 async 异步函数返回值的状态是 fulfilled。 - 如果返回值是一个 Promise,那么 async 异步函数返回值的状态由 Promise 决定。
- 如果返回值是一个 thenable 对象,那么 async 异步函数返回值的状态由 then 方法决定。
async function fn() {
return 1
// 相当于
// Promise.resolve(1)
}
fn().then(res => {
console.log(res) // 1
})
async 异步函数中发生错误:
如果 async 异步函数中发生错误,会中断代码的执行,并且将这个错误抛出,返回值的状态会变为 rejected。
若不捕获错误,将会一层层向上传递,直到被浏览器捕获。
async function fn() {
console.log(1)
'Hello'.filter()
console.log(2)
}
fn().catch(err => {
console.log(err)
})
async 异步函数中的 await 关键字:
await:意思是等待。可以在 async 异步函数内部使用 await 关键字,后面跟一个表达式,它会等待表达式执行完之后才进行下一步操作。
-
如果是普通的表达式,其实和不使用 await 没有什么区别。
async function fn() { // 会依次打印 1、2、3、4 await [1,2,3].forEach(item => console.log(item)) console.log(4) } fn()
async function fn() { // 发生错误,不会打印 2 await 'Hello'.filter() console.log(2) } // 捕获异步函数内部发生的错误 fn().catch(err => { console.log(err) })
-
通常来说, await 后面跟着的是一个返回 Promise 的表达式。
- await 会等到后面跟着的 Promise 的状态变为 fulfilled 之后,才继续执行下面的代码。
function asyncFn() { return new Promise(resolve => { setTimeout(() => { console.log(1) resolve() }, 2000) }) } async function fn() { // 等待 2 秒钟打印 1 之后,才会打印 2 await asyncFn() console.log(2) } fn()
- 如果后面跟着的 Promise 的状态变为了 rejected,会中断 async 异步函数的执行,将错误抛出,并且 async 异步函数返回值的状态变为 rejected。
function asyncFn() { return new Promise((resolve, reject) => { setTimeout(() => { console.log(1) reject('出错了') }, 2000) }) } async function fn() { // 等待 2 秒钟打印 1 之后,然后抛出错误;中断了异步函数的执行,不会打印 2 await asyncFn() console.log(2) } // 捕获异步函数内部发生的错误 fn().catch(err => { console.log(err) })
- await 会等到后面跟着的 Promise 的状态变为 fulfilled 之后,才继续执行下面的代码。
await 的返回值:
await 返回的是后面表达式的值。
async function fn() {
const result = await 1 + 2
console.log(result) // 3
}
f()
async function fn() {
const result = await Promise.resolve(1)
console.log(result) // 1
}
f()