一、定义
Async函数是Generator函数的语法糖,但相较来说比Generator函数更强大一些。主要用于1解决一次异步调用异步函数的问题,即当第一个异步调用结束后,再调用第二个异步函数;等第二个调用完成后再调用第三个的这种情况。在以往的写法里,需要进行回掉函数多层嵌套才能实现,但这种写法会导致多层回调函数嵌套,既不方便维护,也不方便解决。而新的写法可以解决以上的这些问题,将其变成类似同步函数一样的写法,从而能够极大的减轻代码的复杂度。
二、函数示例
使用Generator函数实现依次读取两个文件,代码如下:
写成async函数,就应该是下面这样:
一比较就会发现,async函数就是将Generator函数的星号(*)替换成async,将yield替换成await而已。
三、Async函数的优点
通过比较Async函数和Generator函数的区别,可以明显发现,前者对后者的改进,体现在以下三点:
(1)内置执行器。Generator函数的执行必须依靠执行器,所以才有了co函数,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行:var result = asyncReadFile();
(2)更好的语义。async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性。co函数库约定,yield命令后面只能是Thunk函数或Promise对象,而async函数的await命令后面,可以跟Promise对象和原始类型的值(数值,字符串和布尔值,但这时等同于同步操作)。
四、Async函数的几种写法
这里的写法不是函数内的写法,而是函数本身的写法:
①函数声明(声明式):async在function前
async function foo() {
// some code...
}
②函数表达式(赋值式):async在function前
let foo = async function () {
// some code...
}
③对象属性(属性式):async在function前
let foo = {
bar: async function () {
// some code...
}
}
④对象属性简写:async在函数名前
let foo = {
async bar () {
// some code...
}
}
⑤箭头函数:
let foo = async () => {
// some code...
}
⑥Class写法:记得先new一个实例才能用
class Foo {
async bar() {
// some code...
}
}
五、Async函数的实现
async函数的实现,就是将Generator函数和自动执行器包装在一个函数里。
所有的async函数都可以写成上面的第二种形式,其中的spawn函数就是自动执行器。下面是spawn函数的实现,基本就是前文自动执行器的翻版。
六、Async函数的用法
同Generator函数一样,async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。下面是一个例子:
上面代码是一个获取报价的函数,函数前面的async关键字,表明该函数内部有异步操作,调用该函数时,会立即返回一个Promise函数。
七、补充说明
1、隐式转换:当await后面跟的不是Promise对象,而是基本类型时,该值会被await通过Promise.resolve
隐式转换。事实上,可以被转换的包括例如Boolean、String、Number、对象、数组等,甚至可以支持自定义类型。
2、await函数的限制:await所在的位置只能是async函数的直接所在位置,而不能是async函数外,或者是async函数内部的函数
3、返回值的状态变化:async函数的返回值,是一个Promise对象,即有pending、resolved、rejected三种状态,当函数执行完毕的时候。pending状态变化。