(译文)学习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
作者知乎/公众号:前端疯
(译文)学习ES6非常棒的特性——Async / Await函数的更多相关文章
- (译文)学习ES6非常棒的特性-深入研究var, let and const
Var var firstVar; //firstVar被声明,它的默认值是undefined var secondVar = 2; //secondVar被声明,被赋值2 先看一个例子: var i ...
- (译文)学习ES6非常棒的特性-字符串常量基础
字符串常量基础 在ES2015之前我们是这么拼接字符串的: var result = 10; var prefix = "the first double digit number I le ...
- 使用ES6新特性async await进行异步处理
我们往往在项目中会遇到这样的业务需求,就是首先先进行一个ajax请求,然后再进行下一个ajax请求,而下一个请求需要使用上一个请求得到的数据,请求少了还好说,如果多了,就要一层一层的嵌套,就好像有点c ...
- 微信小程序捕获async/await函数异常实践
背景 我们的小程序项目的构建是与web项目保持一致的,完全使用webpack的生态来构建,没有使用小程序自带的构建功能,那么就需要我们配置代码转换的babel插件如Promise.Proxy等:另外, ...
- ES6非常棒的特性-解构
https://blog.csdn.net/maoxunxing/article/details/79772946
- .net 4.5 新特性 async await 一般处理程序实例
using System; using System.Collections.Generic; using System.Linq; using System.Threading; using Sys ...
- ES8之async/await学习随笔
详细学习参考文档: 阮一峰老师的博客,覆盖知识点ES6/7/8/9,本篇学习笔记对阮老师的关于async/await文档中的知识点进行分点总结 在ES8中加入async/await新特性后,很明显带来 ...
- async/await,了解一下?
上一篇博客我们在现实使用和面试角度讲解了Promise(原文可参考<面向面试题和实际使用谈promise>),但是Promise 的方式虽然解决了 callback hell,但是这种方式 ...
- ES7 Async/Await 陷阱
什么是Async/Await ES6新增了Promise函数用于简化项目代码流程.然而在使用promise时,我们仍然要使用callback,并且并不知道程序要干什么,例如: function doS ...
随机推荐
- studio设置File Templates
从项目的整体风格考虑,对所有类要进行必要的说明,就注释说明来说首先需要说明是作者,文件创建时间,业务功能说明,这几项是基本的内容,而添加这些说明内容以前可能手动的添加文件标题头,这种做法现在都非常过时 ...
- C# 图解教程 第三章 类型、存储和变量
类型.存储和变量 C#程序是一组类型声明类型是一种模板实例化类型数据成员和函数成员预定义类类型用户定义类型栈和堆 栈堆 值类型和引用类型 存储引用类型对象的成员C#类型的分类 变量静态类型和dynam ...
- 一个小的tab切换插件
1//使用 var t1=new Tab({ etype:'onmou',//默认点击触发,如果事件写错了,当作单击 autoplay:2000,//有时间值(按照事件自动播放)和false(不自动播 ...
- 可重复执行的SQL Script
问题 在工作中偶尔会遇到这样的问题:SQL script重复执行时会报错. 理想的状态下,SQL script跑一遍就够了,是不会重复执行的,但是实际情况往往很复杂. 比如Dev同学在开发时在A环境把 ...
- #YCB#待做题目与填坑资料
各种填坑资料(qwq) 主席树(by YL)戳 树套树(by ZSY)戳 不要问我这些题咋来的(查大佬的水表呗) 题目列表: [HDU5977]Garden of Eden [BZOJ2752][HA ...
- 【BZOJ2186】沙拉公主的困惑(数论)
[BZOJ2186]沙拉公主的困惑(数论) 题面 BZOJ 题解 考虑答案是啥 先假设\(n=m\) 现在求的就是\(\varphi(m!)\) 但是现在\(n!\)是\(m!\)的若干倍 我们知道 ...
- 【CJOJ1603】【洛谷1220】关路灯
题面 Description 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老常就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉 ...
- Poj3683:Priest John's Busiest Day
题意 n对夫妻要结婚,第i对夫妻结婚的婚礼持续时间为[Si, Ti],他们会举行一个仪式,仪式时间为Di,这个仪式只能举行在开头或者结尾举行,要么[Si, Si+Di],要么[Ti-Di, Ti],然 ...
- 解决Android Studio 3.0导入module依赖后unable to merge index
解决Android Studio 3.0导入module依赖后unable to merge index 项目需要使用im, 在项目里导入了腾讯im的几个module依赖, 项目无法编译, 报错una ...
- LeetCode之Easy篇 ——(7)Reverse Integer
7.Reverse Integer Given a 32-bit signed integer, reverse digits of an integer. Example 1: Input: Out ...