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)
}
複製程式碼
終於不用不停寫重複程式碼了。。。