美文网首页
async /await 是干嘛的?

async /await 是干嘛的?

作者: 小仙有毒_1991 | 来源:发表于2020-07-07 10:13 被阅读0次

    async和await的定义

    任何一个名称都是有含义的,先从字面意思来理解.async是"异步"的简写,而await可以认为是async wait的简写,于是我们可以理解:

    • async用于申明一个function是异步的
    • await用于等待一个异步方法执行完成

    async起什么作用

    这个问题的关键在于,async函数是如何处理它的返回值的!
    我们当然希望它可以直接通过return语句返回我们想要的结果,可如果是这样,似乎就没await什么事儿了.所以让我们写段代码来试试,看它到底会返回什么

    async function testAsync() {
      return 'hello';
    }
    const result = testAsync();
    console.log(result)  // promise{<resolved>:'hello'};
    
    

    上面代码显示,最后输出的是一个promise对象.所以 async函数返回的是一个Promise对象,从 文档 中也可以得到这个信息.async函数(包括函数语句,函数表达式,Lambda表达式)会返回一个Promise对象.如果函数体中return一个直接量,async会把这个直接量通过Promise.resolve()封装成一个Promise对象.

    async函数返回的是一个Promise对象,所以在最外层不能用await获取其返回值的情况下,我们当然应该用原来的方式:then()链来处理这个Promise对象,就像这样

    testAsync().then( v => {
      console.log(v) // hello
    })
    
    

    现在回过头来想下,如果async函数没有返回值,又改如何?很容易想到,它会返回
    Promise.resolve(undefined)

    联想一下Promise的特点 --- 无等待,所以在没有await的情况下执行async函数,它会立即执行,返回一个Promise对象,并且,绝不会阻塞后面的进程,这和普通返回Promise对象的函数并无不同

    那么下一个关键点就在于await关键字了

    await到底在等啥

    一般来说,都认为await是在等待一个async函数完成.不过按照语法说明,await等待的是一个表达式,这个表达式的计算结果是一个Promise对象或其他说明值(换句话说,就是没有限定)

    因为async返回的是一个Promise对象,所以await可以用于等待一个async函数的返回值---这也可以说是await在等async函数,但要清楚,它等的其实是一个返回值.注意await不仅仅用于等待Promise对象,它可以等待任意表达式的返回值,所以,await后面实际是可以接普通函数调用或者直接量的.所以下面这个示例是可以正确运行的

    async function getSomething() {
      return 'getSomething';
    }
    
    async function testAsync() {
      return Promise.resolve('hello');
    }
    
    async function test() {
      const v1 = getSomething();
      const v2 = testAsync();
      console.log(v1,v2)
    }
    
    test(); // Promise{<resolved>:'getSomething'}  Promise{<pending>}
    
    

    await等到了要等的,然后呢

    await等到了它要等的东西,一个Promise对象,或者其他值,然后呢?我不得不先说,await是一个运算符,用于组成表达式,await表达式的运算结果取决于它等的东西

    如果它等到的不是一个Promise对象,那await表达式的运算结果就是它等到的东西

    如果它等到的是一个Promise对象,那await就忙起来了,await会阻塞后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果

    image

    async和await帮我们干了啥

    作个简单的比较

    上面已经说明了,async会将后面的函数()的返回值封装成一个Promise,而await会等待这个Promise完成,并将resolve的值返回出来

    现在举例,用setTimeout模拟耗时的异步操作,先来看看不用async和await会怎么写

    function takelongTime() {
      return new Promise( resolve => {
        setTimeout(() = > {
          console.log('loong_time_value')
        },1000)
      })
    }
    
    takeLongTime().then( v => {
      console.log(v)
    })
    
    

    现在改用async和await以后, 会是这样:

    function takeLongTime() {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log('long_time_value');
        })  
      })
    }
    
    async function test() {
      const v = await takeLongTime();
      console.log(v);
    }
    
    test();//'long_time_value'
    
    

    这里takeLongTime函数没有用async申明.实际上,takeLongTime本身就是返回的Promise对象,加不加async结果都一样.

    上面两种方式,都是对异步调用的处理(实际都是对promise对象的处理)差别并不明显,甚至使用async和await,代码看起来更多,那么它的优势到底在哪里?

    async和await的优势在于处理then链

    单一的Promise链并不能发现async和await的优势,它的优势在于处理由多个Promise组成的then链

    假设一个业务,分多个步骤完成,每一个步骤依赖上一个步骤的结果,我们依然用setTimeout来模拟异步操作

    /**
      *传入参数n,表示这个函数需要执行的时间(毫秒)
      *得到的结果是n + 200,这个值将用于下一步骤
      */
    function takeLongTime() {
      return new Promise(resolve => {
        setTimeout(() => resolve(n + 200),n)
      })
    }
    function stemp1() {
      console.log(`stemp1 with ${n}`)
      return takeLongTime(n);
    }
    function stemp2() {
      console.log(`stemp2 with ${n}`)
      return takeLongTime(n);
    }
    function stemp3() {
      console.log(`stemp3 with ${n}`)
      return takeLongTime(n);
    }
    
    

    现在用promise方法来实现这三个步骤的处理(使用async & await语法糖取代 then)

    function doIt() {
      console.time('doIt');
      const time1 = 300;
      stemp1(time1)
             .then(time2 => stemp2(time2))
             .then(time3 => stemp3(time3))
             .then(result => {
                console.log(`result is ${result}`)
                console.timeEnd('doIt')
              }) 
    }
    doIt();
    输出结果 result 是 step3() 的参数 700 + 200 = 900。doIt() 顺序执行了三个步骤,
    一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 计算的结果基本一致。
    
    

    下面用async和await来实现

    async function doIt() {
      console.log('doIt');
      const time1 = 300;
      const time2 = await stemp1(time1);
      const time3 = await stemp2(time2);
      const result = await stemp3(time3);
      console.log(`result is ${result}`)
      console.timeEnd('doIt');
    }
    
    

    结果和之前的promsise实现是一致的,这样做的好处就是代码清晰了很多,几乎跟同步代码是一样的
    原文摘自 《理解JavaScript 的 async/await》
    转自:灬劣徒 《JS | async和await》

    相关文章

      网友评论

          本文标题:async /await 是干嘛的?

          本文链接:https://www.haomeiwen.com/subject/anzoqktx.html