美文网首页
async/await 整理总结

async/await 整理总结

作者: 人猿Jim | 来源:发表于2021-09-11 22:39 被阅读0次
    from DSマイル

    参考:红宝书 es6入门

    async

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

    async function fn(args) {
      // ...
    }
    
    // 等同于
    
    function fn(args) {
      return spawn(function* () {
        // ...
      });
    }
    
    // 自动执行器
    function spawn(genF) {
      return new Promise(function(resolve, reject) {
        const gen = genF();
        function step(nextF) {
          let next;
          try {
            next = nextF();
          } catch(e) {
            return reject(e);
          }
          if(next.done) {
            return resolve(next.value);
          }
          Promise.resolve(next.value).then(function(v) {
            step(function() { return gen.next(v); });
          }, function(e) {
            step(function() { return gen.throw(e); });
          });
        }
        step(function() { return gen.next(undefined); });
      });
    }
    

    特性

    1. async关键字可以让函数具有异步特征,但总体上还是同步求值。

    异步函数如果不包含await关键字,就和普通函数没什么区别

    async function foo(){
      console.log(1)
    } 
    foo()
    console.log(2)
    // 1
    // 2
    
    async function bar(){
      console.log(1)
      await console.log(2)
      console.log(4)
    }
    bar();
    console.log(3)
    // 1
    // 2
    // 3
    // 4
    
    1. 返回值期待一个实现thenable接口的对象,这个对象可以提供给then()中的处理程序解包,如果不是就返回已经解决的Promise
    async function baz(){
      return {
         then(callback){
             callback('baz')
         }
      }
    }
    baz().then(console.log)
    // baz
    

    3.async内部报错机制:
    ①在没有显式返回Promise <rejected>情况下,依然是返回resolved态的promise,且里面异步错误无法捕获(Uncaught)。

    async function p2(){
      Promise.reject('1')
    }
    p2()
    
    // Promise {<resolved>: undefined}
    // Uncaught (in promise) 1
    
    async function p3(){
        return Promise.reject('2')
    }
    p3().catch(console.log)
    // 2
    
    

    ②在异步函数内部抛出错误,会返回拒绝的promise

    async function foo(){
      console.log(1)
      throw 3
    }
    console.log(2)
    foo().catch(console.log)
    // 1
    // 2
    // 3
    

    ③ 遇到await捕获的报错或者抛出错误的同步操作,会返回rejected的Promise,并且停止函数内后面代码的执行。

    单独的Promise.reject()不会被异步函数捕获,而会抛出未捕获的错误。不过,对拒绝的Promise使用await则会释放(unwrap)错误值(将拒绝的Promise返回)

    // await遇到返回错误的promise
    async function foo(){
      console.log(1)
      await Promise.reject(3)
      console.log(4) // 不执行
    }
    console.log(2)
    foo().catch(console.log)
    // 1 
    // 2
    // 3
    
    //  await遇到同步操作情况
    async function foo(){
      console.log(1)
      await (()=>{throw 3})()
    }
    console.log(2)
    foo().catch(console.log)
    // 1
    // 2
    // 3
    

    await

    作用:异步函数中的暂停和恢复的标志,await关键字会根据表达式是否是Promise来决定暂不暂停执行后面的代码(async函数中),让出js运行时的执行线程。与生成器函数中yield关键字作用是一样的。await关键字会尝试“解包”对象的值,然后把值传给表达式,在异步恢复异步函数的执行。
    await - JavaScript | MDN

    解包,类似于await 把这个promise主动then了一层,然后取出值

    限制:
    ①必须在异步函数中使用
    ②异步函数特征不会扩展到嵌套函数,因此await关键字只能直接出现在异步函数的定义中

    // 解包
    async function foo(){
      console.log(await Promise.resolve('foo'))
    }
    foo()
    console.log(1)
    // 1
    // foo     (异步打印)
    
    async function baz(){
      await new Promise(res =>{
        settimeout(res,1000)
      })
      console.log('baz')
    }
    baz()
    // baz (1000毫秒后)
    
    async function re1(){
        console.log(1);
        console.log(await Promise.resolve(2)) // 让出执行权,交给异步消息队列
    }
    async function re2(){
        console.log(3);
        console.log(await 4)  // 让出执行权,交给异步消息队列
    }
    re1();
    re2();
    console.log(5)
    // 1
    // 3
    // 5
    // 2
    // 4
    

    await关键字期待thenable接口的对象,这个对象由await去解包,如果不是,就会把这个值当作已经解决的promise,然后去解包

    async function foo(){
      const thenable = {
        then(callback){
           callback('foo')
        }
      }
      console.log(await thenable)
    }
    foo()
    // foo
    
    async function bar(){
      console.log(await 'bar')
    }
    bar()
    // bar
    

    异步错误捕获

    js的同步错误捕获机制很强大,基本 try catch可以捕获所有同步错误,当然,是在try catch上下文中运行的同步错误。

    参考:精读《捕获所有异步 error》
    文章中讲了许多捕获异步异常的方法,详细可以点进去看,在这我只做总结

    1. async函数因为返回promise,基本用catch可以捕获到异步异常
    2. async函数体内用try catch 结构捕获await异常(常用)
    3. 如果支持await,可以用await一直链式解包
    async function main() {
      try {
        const val1 = await firstStep();
        const val2 = await secondStep(val1);
        const val3 = await thirdStep(val1, val2);
    
        console.log('Final: ', val3);
      }
      catch (err) {
        console.error(err);
      }
    }
    

    需要关注的是下面这种情况,即异步之中还有异步,或者dom事件监听

    new Promise(() => {
      setTimeout(() => {
        throw new Error('err') // uncaught 无法捕获
      }, 0)
    }).catch((e) => {
      console.log(e)
    })
    
    document.querySelector('button').addEventListener('click', () => {
      throw new Error('err') // uncaught 无法捕获
    })
    

    解决办法如下:
    ①通过函数体内 try catch 来捕获
    ②设置全局错误监控

    window.addEventListener('error')
    window.addEventListener('unhandledrejection')
    

    ③Promise可以写成 Promise Chain

    new Promise((res, rej) => {
      setTimeout(res, 1000) // 1
    })
      .then((res, rej) => {
        throw Error('err')
      })
      .catch((error) => {
        console.log(error)
      })
    

    相关文章

      网友评论

          本文标题:async/await 整理总结

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