一般在一个项目开始之前,我们一般会对现有的框架做一定功能上的丰富,比如对ajax请求功能的二次封装,封装的功能可能包含了:通用错误处理,请求过滤,响应过滤等等。如果我们封装的函数叫request,那么业务中触发一个ajax请求的流程大致如图:
通常,这样的流程处理能满足需求,然而,更多的情况,我们希望request的返回数据,经过request预处理后,首先交由业务代码这边自行判断是否合法,是否需要处理错误,如果不合法,且自己不打算处理错误,则再抛出错误,这样的话,就符合很多后端框架的流程了,业务层的错误,先自己catch,要么处理,要么往框架抛,框架统一处理,流程大致如图:
这样的话,所有的错误,业务层有了优先处理的权利,不需要自行处理的情况才交由框架做通用处理。
当然,在javascript中,异步错误的处理不能简简单单地通过window.onerror
可以搞定的,在vue下改造,具体的思路是将我们需要按新的流程处理的函数处理成async函数,这样,我们就能用promise的那套错误处理机制来处理了。
具体实现看代码:
const install = (Vue, { handler = () => {} }) => {
Vue.mixin({
beforeCreate() {
const options = this.$options;
const { methods = {}, catchAsyncError } = options;
if (!catchAsyncError) return;
Object.keys(methods).forEach(key => {
const fn = methods[key];
options.methods[key] = function(...args) {
const ret = fn.apply(this, args);
if (ret && typeof ret.catch === "function") {
return ret.catch(handler);
}
return ret;
};
});
}
});
};
export default {
install
};
// 使用插件
Vue.use(asyncErrorCatch, {
handler(err) {
console.log("catch async error:", err.message);
}
});
在组件内我们这样使用:
export default{
name: "MyPage",
catchAsyncError: true,
methods: {
async fn() {
// Will catch by plugin
throw new Error("this is an async error")
},
test() {
// Will catch by Vue.config.errorHandler
throw new Error('sync error')
}
}
}
插件放GitHub了 :https://github.com/Elity/VueGlobalError
待解决问题:
如下代码中,通过dom事件触发a
方法,a
方法内部中调用异步的b
方法,而b
方法中的错误没到a
方法内就被处理了,理想状态是a
方法内应该可以catch
到b
方法抛出的错误
{
methods:{
async a(){
this.b()
},
async b(){
throw new Error("Error")
}
}
}