promise
promise 的出现,提供了优雅的异步解决方式,但是,多个连续继发 promise 写法依然繁琐。
let promise = new Promise(function(resolve, reject){
// ...
if(/* 异步任务执行成功 */) {
resolve(value)
} else {
reject(error)
}
})
promise.then(v => {}).catch(e => {})
复制代码
async
es6 之后又新增了 async 函数来优化异步写法,语义化更明确,写法更优雅,但是错误捕获比较麻烦,一般都得使用 try catch 来捕获错误,具体优点参考阮老师博客 async 函数
function promiseFunc = function(){
return new Promise(function(resolve, reject){
// ...
if(/* 异步任务执行成功 */) {
resolve(value)
} else {
reject(error)
}
})
}
async func(){
let res = await promiseFunc()
}
// 错误捕获
async func(){
try{
let res = await promiseFunc()
}catch(err){
alert(err)
}
}
复制代码
错误捕获优化
如下是工作中 react + mobx 项目中 action 的代码
class Actions {
@action
async deleteModel(params) {
try {
await this.post(apis.API_DEPLOY_DELETE, params)
this.getDeployList(this.store.searchParams)
} catch (e) {
message.error(e.message || '出错了!请稍后重试')
}
}
@action
async getDirChain(params) {
try {
let r = await this.post(apis.API_DEPLOY_DIR_CHAIN, params)
runInAction(() => {
this.store.dirChain = r
})
} catch (e) {
message.error(e.message || '出错了!请稍后重试')
}
}
}
复制代码
如上代码,两个 action 都是向后端异步请求数据, 每个 action 函数中都用了 try catch 函数,这样重复写了几十个 action 函数
必须干掉 try catch
错误捕获装饰器尝试
装饰器简洁方便,首先尝试, class 方法装饰器函数如下
const tryCatch = msg => (target, name, descriptor) => {
const original = descriptor.value
if (typeof original === 'function') {
descriptor.value = async function(...args) {
try {
const result = await original.apply(this, args)
return result
} catch (e) {
message.error(e.message || msg || '出错了!请稍后重试')
}
}
}
return descriptor
}
复制代码
如上代码,封装 tryCatch 装饰器来对每个 action 函数添加 try catch 错误捕获。
属性方法装饰器中
- target 指向 class 实例
- name 是被装饰的方法名
- descriptor 是方法的属性修饰符
我们可以通过 descriptor.value 获取到被装饰的方法,在 try catch 中执行函数,捕获错误或者返回结果
为了灵活提示错误信息,装饰器参数 msg 用来传入自定义提示文本
- 用法(该用法是错误的)
@tryCatch // @tryCatch('运行出错')
@action
async getDirChain(params) {
let r = await this.post(apis.API_DEPLOY_DIR_CHAIN, params)
runInAction(() => {
this.store.dirChain = r
})
}
复制代码
以上对 async 函数进行错误捕获的用法是错误的
如上的写法是错误的,这种装饰器只能对
同步代码
产生作用,异步的是无效的,之前理解错误了
最后还是解决了 try catch 问题
直接 async await 函数封装就行了,简单的问题想复杂了。。。
定义请求执行公共函数
/**
* @param {string} method request method; ('get', 'post')
* @param {string} api request url
* @param {object} params payload
* @memberof BaseActions
*/
request = async (method, api, params = {}) => {
const requestFunc = async () => {
let r = null
try {
r = await this[method](api, params)
} catch (e) {
message.error(e.message)
}
return r
}
return await requestFunc()
}
复制代码
原有包含 try catch 重复代码函数修改
@action
async getDirChain(params) {
let r = await this.request('get', apis.API_DEPLOY_DIR_CHAIN, params)
r && runInAction(() => this.store.dirChain = r)
}
复制代码
终于不用不停写重复代码了。。。