介绍
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async 函数是什么?一句话,它就是 Generator 函数的语法糖。
// 请求网络数据(伪代码)
// generator 函数
const requestDataGenerator = function* () {
const res1 = yield requestData(url1)
const res2 = yield requestData(url2)
console.log(res1)
console.log(res2)
}
// async 函数
const asyncRequestData = async function() {
const res1 = await requestData(url1)
const res2 = await requestData(url2)
console.log(res1)
console.log(res2)
}
一比较就会发现,async
函数就是将 Generator 函数的星号(*
)替换成async
,将yield
替换成await
,仅此而已。async
函数对Generator 函数的改进,体现在以下四点:
内置执行器
Generator 函数的执行必须靠执行器,所以才有了co
模块,而async
函数自带执行器。也就是说,async
函数的执行,与普通函数一模一样,只要一行:
asyncRequestData()
上面的代码调用了asyncRequestData
函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用next
方法,或者用co
模块,才能真正执行,得到最后结果。
更好的语义
async
和await
,比起星号和yield
,语义更清楚了。async
表示函数里有异步操作,await
表示紧跟在后面的表达式需要等待结果。
更广的适用性
co
模块约定,yield
命令后面只能是 Thunk 函数或 Promise 对象,而async
函数的await
命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
返回值是 Promise
async
函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then
方法指定下一步的操作。
进一步说,async
函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await
命令就是内部then
命令的语法糖(即表达式的值就是返回的 Promise then 中携带的参数,例如上述 async
函数中 res1、res2 就是一个具体值,而不是 Promise)。
语法
返回 Promise 对象
async
函数返回一个 Promise 对象,可以使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
下述是一个延迟 2s 打印的一个例子。
async function printAsync() {
const res = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('这是异步返回的数据')
}, 2000)
})
return res
}
printAsync().then(res => {
console.log(res)
})
Promise 对象的状态变化
async
函数返回的 Promise 对象,必须等到内部所有await
命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return
语句或者抛出错误。也就是说,只有async
函数内部的异步操作执行完,才会执行then
方法指定的回调函数。
async function getTitle(url) {
let response = await fetch(url);
let html = await response.text();
return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"
上面代码中,函数getTitle
内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行then
方法里面的console.log
。
错误处理
如果await
后面的异步操作出错,那么等同于async
函数返回的 Promise 对象被reject
。