美文网首页
async/await

async/await

作者: 我是哈斯 | 来源:发表于2019-08-12 14:23 被阅读0次

    ES7的async/await语法在2016年就已经提出来了,惭愧的是我最近才接触使用,,下面来聊聊

    解决了什么问题

    在async/await之前,我们有三种方式写异步代码

    1. 嵌套回调

    2. 以Promise为主的链式回调

    3. 使用Generators

    但是,这三种写起来都不够优雅,ES7做了优化改进,async/await应运而生,async/await相比较Promise 对象then 函数的嵌套,与 Generator 执行的繁琐(需要借助co才能自动执行,否则得手动调用next() ), Async/Await 可以让你轻松写出同步风格的代码同时又拥有异步机制,更加简洁,逻辑更加清晰。

    async/await特点

    1. async/await更加语义化,async 是“异步”的简写,async function 用于申明一个 function 是异步的; await,可以认为是async wait的简写, 用于等待一个异步方法执行完成;

    2. async/await是一个用同步思维解决异步问题的方案(等结果出来之后,代码才会继续往下执行)

    3. 可以通过多层 async function 的同步写法代替传统的callback嵌套

    async function语法

    • 自动将常规函数转换成Promise,返回值也是一个Promise对象

    • 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数

    • 异步函数内部可以使用await

    async function name([param[, param[, ... param]]]) { statements }
    name: 函数名称。
    param:  要传递给函数的参数的名称
    statements: 函数体语句。
    返回值: 返回的Promise对象会以async function的返回值进行解析,或者以该函数抛出的异常进行回绝。
    
    
    image

    await语法

    • await 放置在Promise调用之前,await 强制后面点代码等待,直到Promise对象resolve,得到resolve的值作为await表达式的运算结果

    • await只能在async函数内部使用,用在普通函数里就会报错

    [return_value] = await expression;
    
    expression:  一个 Promise  对象或者任何要等待的值。
    
    返回值:返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。
    
    
    image

    错误处理

    在async函数里,无论是Promise reject的数据还是逻辑报错,都会被默默吞掉,所以最好把await放入try{}catch{}中,catch能够捕捉到Promise对象rejected的数据或者抛出的异常

    function timeout(ms) {
    
      return new Promise((resolve, reject) => {
    
        setTimeout(() => {reject('error')}, ms);  //reject模拟出错,返回error
    
      });
    
    }
    
    async function asyncPrint(ms) {
    
      try {
    
         console.log('start');
    
         await timeout(ms);  //这里返回了错误
    
         console.log('end');  //所以这句代码不会被执行了
    
      } catch(err) {
    
         console.log(err); //这里捕捉到错误error
    
      }
    
    }
    
    asyncPrint(1000);
    
    

    如果不用try/catch的话,也可以像下面这样处理错误(因为async函数执行后返回一个promise)

    function timeout(ms) {
    
      return new Promise((resolve, reject) => {
    
        setTimeout(() => {reject('error')}, ms);  //reject模拟出错,返回error
    
      });
    
    }
    
    async function asyncPrint(ms) {
    
      console.log('start');
    
      await timeout(ms)
    
      console.log('end');  //这句代码不会被执行了
    
    }
    
    asyncPrint(1000).catch(err => {
    
        console.log(err); // 从这里捕捉到错误
    
    });
    
    

    如果你不想让错误中断后面代码的执行,可以提前截留住错误,像下面

    function timeout(ms) {
    
      return new Promise((resolve, reject) => {
    
        setTimeout(() => {
    
            reject('error')
    
        }, ms);  //reject模拟出错,返回error
    
      });
    
    }
    
    async function asyncPrint(ms) {
    
      console.log('start');
    
      await timeout(ms).catch(err => {  // 注意要用catch
    
    console.log(err) 
    
      })
    
      console.log('end');  //这句代码会被执行
    
    }
    
    asyncPrint(1000);
    
    

    使用场景

    多个await命令的异步操作,如果不存在依赖关系(后面的await不依赖前一个await返回的结果),用Promise.all()让它们同时触发

    function test1 () {
        return new Promise((resolve, reject) => {
    
            setTimeout(() => {
    
                resolve(1)
    
            }, 1000)
    
        })
    
    }
    
    function test2 () {
    
        return new Promise((resolve, reject) => {
    
            setTimeout(() => {
    
                resolve(2)
    
            }, 2000)
    
        })
    
    }
    
    async function exc1 () {
    
        console.log('exc1 start:',Date.now())
    
        let res1 = await test1();
    
        let res2 = await test2(); // 不依赖 res1 的值
    
        console.log('exc1 end:', Date.now())
    
    }
    
    async function exc2 () {
    
        console.log('exc2 start:',Date.now())
    
        let [res1, res2] = await Promise.all([test1(), test2()])
    
        console.log('exc2 end:', Date.now())
    
    }
    
    exc1();
    
    exc2();
    
    

    exc1 的两个并列await的写法,比较耗时,只有test1执行完了才会执行test2

    你可以在浏览器的Console里尝试一下,会发现exc2的用Promise.all执行更快一些

    image

    兼容性

    image

    在自己的项目中使用

    通过 babel 来使用。

    只需要设置 presets 为 stage-3 即可。

    安装依赖:

    npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime

    修改.babelrc:

     "presets": ["es2015", "stage-3"],
    
     "plugins": ["transform-runtime"]
    
    

    这样就可以在项目中使用 async 函数了。

    相关文章

      网友评论

          本文标题:async/await

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