zoukankan      html  css  js  c++  java
  • (译文)学习ES6非常棒的特性——Async / Await函数

    try/catch

    在使用Async/Await前,我们可能这样写:

    const main = (paramsA, paramsB, paramsC, done) => {
      funcA(paramsA, (err, resA) => {
        if (err) return done(err)
        return funcB(paramsB, (err, resB) => {
          if (err) return done(err)
          funcC(paramsC, (err, resC) => {
            if (err) return done(err)
            // (╯°□°)╯︵ ┻━┻
            return done(null, { resA, resB, resC })
          })
        })
      })
    }

    采用了Async/Await后:

    const main = async (paramsA, paramsB, paramsC) => {
      const resA = await funcA(paramsA)
      const resB = await funcB(paramsB)
      const resC = await funcC(paramsC)
      // (T.T)/
      return { resA, resB, resC }
    }

    然后你会发现,我们没有处理错误异常的情况,然后你可能会这么写:

    const main = async (paramsA, paramsB, paramsC) => {
      let resA
      let resB
      let resC
      try {
        resA = await funcA(paramsA)
      } catch (error) {
        throw error
      }
      try {
        resB = await funcB(paramsB)
      } catch (error) {
        throw error
      }
      try {
        resC = await funcC(paramsC)
      } catch (error) {
        throw error
      }
      // (o.o;)
      return { resA, resB, resC }
    }

    可能你不需要单独处理每个错误,然后你就这么写:

    const main = async (paramsA, paramsB, paramsC) =>
      try {
        const resA = await funcA(paramsA)
        const resB = await funcB(paramsB)
        const resC = await funcC(paramsC)
          // (^.^')
        return { resA, resB, resC }
      } catch (error) {
        throw error
      }
    }

    但是,很快滴,你发现代码报了这样一个错误:(注意如果你用了Node.js,可能对这个错误不陌生)

    (node: xxx) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: y): Error: some sort of error
    (node: xxx) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    // (-.-;)

    然后你会想,我草,哪里的原因。然后你花了20多分钟,去找问题。问题很简单就是:
    你抛出了一个异常,但是你没有捕捉它和处理它。

    因为Async/Await函数返回的是一个Promise,所以我们想下怎么解决它:

    const main = async (paramsA, paramsB, paramsC) => {
      try {
        const resA = await funcA(paramsA)
        const resB = await funcB(paramsB)
        const resC = await funcC(paramsC)
        return { resA, resB, resC }
      } catch (error) {
        // sure it's thrown, but who catches it??
        throw error
      }
    }
    // somewhere else...
    main()
      .then(d => { // do things with the result })
      .catch(e => { // handle that error! })

    在.catch方法里面捕捉错误。但如果我真的想单独处理某个错误呢:

    const main = async (paramsA, paramsB, paramsC) => {
      const resA = await funcA(paramsA)
      const resB = await funcB(paramsB).catch(e => { // things unique to this error })
      const resC = await funcC(paramsC)
      return { resA, resB, resC }
    }
    // ... all we need is this `.catch` to handle all of them.
    main()
      .then(d => { // do things with the result })
      .catch(e => { // handle all other errors!! })

    用Mocha, Sinon, and Chai进行测试

    测试Async / Await函数非常简单,首先,你只要记住这三件事:
    1 不要把异步函数和promise混一起

    const thing = (params, done) => {
      ApiCall(params, async (err, data) => {
        if (err) return done(err)
        const things = await OtherApiCall(data)
        return done(null, things)
      })
    }

    像上面这样,真的会崩溃的。
    2 记住Async / Await返回了一个Promise
    3 如果你在Mocha测试里面返回了promise,mocha测试会处理好它,你不用担心。

    ok.开始:
    我们有一个主文件main.js

    // main.js
    const main = async (paramsA, paramsB, paramsC) => {
      const resA = await apiA.create(paramsA)
      const resB = await apiB.delete(paramsB)
      const resC = await apiC.update(paramsC)
      return { resA, resB, resC }
    }

    然后我们的测试文件就这样写:

    // test.js
    const expect = require('chai').expect
    const sinon = require('sinon')
    const main = require('main.js')
    const apiA = require('apiA')
    const apiB = require('apiB')
    const apiC = require('apiC')
    describe('Main Function', () => {
      let apiAstub
      let apiBstub
      let apiCstub
      beforeEach(() => {
        apiAstub = sinon.stub(apiA, 'create')
        apiBstub = sinon.stub(apiB, 'delete')
        apiCstub = sinon.stub(apiC, 'update')
      })
      afterEach(() => {
        apiAstub.restore()
        apiBstub.restore()
        apiCstub.restore()
      })
      it('should handle errors if apiA.create() fails', () => {
        apiAstub.throws('error for apiA.create()')
        // 在这里处理一下。因为返回的是promise,catch一下就行
        return main('a', 'b', 'c').catch((e) => {
          //mocha会等promise返回或者在这里异常
          expect(e).to.equal('error for apiA.create()')
        })
      })
      it('should handle errors if apiB.delete() fails', () => {
        apiAstub.returns('success a')
        apiBstub.throws('error for apiB.delete()')
        return main('a', 'b', 'c').catch((e) => {
          expect(e).to.equal('error for apiB.create()')
        })
      })
      it('should handle errors if apiC.update() fails', () => {
        apiAstub.returns('success a')
        apiBstub.returns('success b')
        apiCstub.throws('error for apiC.delete()')
        return main('a', 'b', 'c').catch((e) => {
          expect(e).to.equal('error for apiC.create()')
        })
      })
      it('should return the responses of all functions if all api calls succeed', () => {
        apiAstub.returns('success a')
        apiBstub.returns('success b')
        apiCstub.throws('success c')
        return main('a', 'b', 'c').then((res) => {
          expect(res).to.deep.equal({
            resA: 'success a',
            resB: 'success b',
            resC: 'success c',
          })
        })
      })
    })

    不用第三方库,测试用例照写不误。

    Async / Await和Node核心模块一起使用

    你可能会想要这么写:

    const fs = require('fs')
    async function readThings () {
      const file = await fs.readFile('./file.txt', 'utf8')
      // file值不存在
      return file
    }

    但实际上:readFile 并没有返回promise,这样写是有问题的
    很幸运滴是Node.js8 util方法提供了一个method,promisify:

    const fs = require('fs')
    const { promisify } = require('util')
    const readFile = promisify(fs.readFile)
    async function readThings () {
      const file = await readFile('./file.txt', 'utf8')
      // 成功!
      return file
    }

    Async / Await在AWS SDK中使用

    const aws = require('aws-sdk')
    async function getEc2Info () {
      const ec2 = new aws.EC2()
      const instances = await ec2.describeInstances()
      // do things with instances
    }

    如果你像上面那样写,你会发现它不起作用。你会想用util.promisify,但其实它也不能用。
    实际上,这样就行了:

    const aws = require('aws-sdk')
    async function getEc2Info () {
      const ec2 = new aws.EC2()
      const instances = await ec2.describeInstances().promise() // <--
      // Actually do things with instances!
    }

    以上就是今天的内容,感谢阅读。
    原文:https://start.jcolemorrison.com/5-tips-and-thoughts-on-async-await-functions/#testing

    作者知乎/公众号:前端疯

  • 相关阅读:
    搜索能力
    sublimetext中文论坛
    Sublime Text添加插入带当前时间说明
    X86平台简称
    centos 下如何加入sudo 用户
    Git Shell 安装版本
    Git 使用教程
    CentOS 下安装配置mongodb
    Mysql 解决left join 数据重复的问题
    CentOS 下安装翻译软件星际译 StarDict
  • 原文地址:https://www.cnblogs.com/xunxing/p/bcb2eb53ef50a00496a7c5e3e21e3e07.html
Copyright © 2011-2022 走看看