zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    小白必读:闲话HTTP短连接中的Session和Token
    网络编程懒人入门(六):深入浅出,全面理解HTTP协议
    IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?
    致我们再也回不去的 Github ...
    了不起的WebRTC:生态日趋完善,或将实时音视频技术白菜化
    网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门
    盘点微信的前世今生,微信成功的必然和偶然
    微信七年回顾:历经多少质疑和差评,才配拥有今天的强大
    写给小白的实时音视频技术入门提纲
    jenkins使用jacoco插件检测代码覆盖率(八)
  • 原文地址:https://www.cnblogs.com/wangrenmeng/p/10958175.html
Copyright © 2011-2022 走看看