promise 的出現,提供了優雅的異步解決方式,可是,多個連續繼發 promise 寫法依然繁瑣。react
let promise = new Promise(function(resolve, reject){
// ...
if(/* 異步任務執行成功 */) {
resolve(value)
} else {
reject(error)
}
})
promise.then(v => {}).catch(e => {})
複製代碼
es6 以後又新增了 async 函數來優化異步寫法,語義化更明確,寫法更優雅,可是錯誤捕獲比較麻煩,通常都得使用 try catch 來捕獲錯誤,具體優勢參考阮老師博客 async 函數es6
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 函數api
必須幹掉 try catchpromise
裝飾器簡潔方便,首先嚐試, class 方法裝飾器函數以下app
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 錯誤捕獲。異步
屬性方法裝飾器中async
咱們能夠經過 descriptor.value 獲取到被裝飾的方法,在 try catch 中執行函數,捕獲錯誤或者返回結果函數
爲了靈活提示錯誤信息,裝飾器參數 msg 用來傳入自定義提示文本post
@tryCatch // @tryCatch('運行出錯')
@action
async getDirChain(params) {
let r = await this.post(apis.API_DEPLOY_DIR_CHAIN, params)
runInAction(() => {
this.store.dirChain = r
})
}
複製代碼
如上的寫法是錯誤的,這種裝飾器只能對
同步代碼
產生做用,異步的是無效的,以前理解錯誤了
直接 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)
}
複製代碼
終於不用不停寫重複代碼了。。。