async函数

什么是Generator函数。

概念:Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。Generator 函数有多种理解角度。语法上,首先可以把它理解成是一个状态机,封装了多个内部状态。

执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。

 

形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态。Generator 函数最大特点就是可以交出函数的执行权(即暂停执行)。

 

为了更好的理解上面这句话,我决定给大家举个例子

1         function* Generator() {
2             yield '11111111';
3             yield '22222222'
4             return '3333333';
5         }
6 
7         let aaa = Generator();

 
Generator函数和普通函数一样通过函数名+()去调用,但是调用完之后并不执行。返回的也不是函数运行的结果,而是指向内部状态的指针。想要运行Generator函数,需要通过遍历器对象的next方法。
每次调用 next 方法,会返回一个对象,表示当前阶段的信息( value 属性和 done 属性)。value 属性是 yield 语句后面表达式的值,表示当前阶段的值;done 属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。
 
1         let a = aaa.next()
2         let b = aaa.next()
3         let c = aaa.next()
4         let d = aaa.next()
5         console.log(a,b,c,d)

输出结果:  {value: "11111111", done: false}     {value: "22222222", done: false}      {value: "3333333", done: true}     {value: undefined, done: true}

 

想要Generator函数执行下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式或return语句。由此可见,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。也就是上面说的可以交出函数的执行权。

 

async函数

文章最一开始我们就说了async函数就是Generator函数的语法糖。

为什么这么说呢,我还是决定给大家举个例子吧:

(盗用ES6中对比Generator函数和async函数的例子)

 

代码上看起来,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await。

实际上async函数对Generator函数的改进,体现在一下四点:

1.async函数自带执行器,所以执行方式和普通函数的执行方式一样,通过函数名+()的方式执行。

2.async和await比起*和yield在语义上更清楚。

3.co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

4.async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

 

用法

async函数 声明函数中存在异步操作,执行结果返回一个 Promise 对象,可以使用then方法添加回调函数。await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。

当函数执行的时候,遇到await会先等待await后面的函数执行,等待异步操作完成之后再继续执行。

 1         async function consoleA(){
 2             let result = await run(2,3)
 3             console.log("B",result)
 4             return "consoleA 方法"
 5         }
 6         
 7         function run(x,y){
 8             console.log('run 方法')
 9             return x*y
10         }
11         consoleA()
12         .then(res => {
13             console.log(res,'then')
14         })

输出顺序为 : 

  run 方法
  B 6
  consoleA 方法 then

 

注意:

1.async函数在声明形式上和普通函数没有区别,函数声明式,函数表达式,对象方法,class方法和箭头函数等都可以声明async函数。

2.任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。

3.async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

 

我是一个简单又无辜的小问题~~~

 1         function consoleA(){
 2             console.log("A")
 3         }
 4 
 5         async function consoleB(){
 6             await consoleA()
 7             console.log("B")
 8         }  
 9         
10         (function consoleC(){
11             consoleB().then(_ => {
12                 console.log("D")
13             })
14             console.log("C")
15         })()

 

错误处理

上面我们说了,await后面的异步操作异常,那么整个async函数就会全部停止执行。但是有的时候我们又想,可不可以即使前面的异步操作异常,后面的代码还是可以继续执行。

解决办法就是把异步操作放在try catch语句中

例如

 1         async function consoleA(){
 2             try{
 3                 console.log("A")
 4                 await run1()
 5                 await run2()
 6                 await run3()
 7             }catch(e){}
 8             
 9             console.log("运行")
10         }
11         function run1(){
12             throw new Error("错误")
13         }
14         function run2(){
15             throw new Error("错误")
16         }
17         function run2(){
18             throw new Error("错误")
19         }
20         consoleA()

上面代码中异步操作抛出的异常被catch捕获,所以console.log(“运行”)依然可以正常输出。

 

实现原理

async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。

 1 async function fn(args) {
 2   // ...
 3 }
 4 
 5 // 等同于
 6 
 7 function fn(args) {
 8   return spawn(function* () {
 9     // ...
10   });
11 }

所以所有的async函数都可以写成上面例子中下面的那种形式,其中的spawn函数就是自动执行器

 

问题总结:

1.async和await,await会返回异步方法resolve的结果,所以如果用了async和await又需要捕捉异常就需要用到try catch这中可以捕捉错误的机制

2. async 在函数声明前使用async关键词,说明函数中存在异步操作。await 等待代码执行完毕再继续向下执行

3.try catch 异常捕获机制。在try语句中的代码抛出异常,都会在catch中被捕获 。try代码块中只要有一个抛出了异常,就不会在继续向下执行

 

参考链接:http://es6.ruanyifeng.com/#docs/async

原文地址:https://www.cnblogs.com/wangrenmeng/p/10958175.html