编程随想 · 2018 年 03 月 14 日

Vue中异步错误处理

一般在一个项目开始之前,我们一般会对现有的框架做一定功能上的丰富,比如对ajax请求功能的二次封装,封装的功能可能包含了:通用错误处理,请求过滤,响应过滤等等。如果我们封装的函数叫request,那么业务中触发一个ajax请求的流程大致如图:
正常ajax请求流程图
通常,这样的流程处理能满足需求,然而,更多的情况,我们希望request的返回数据,经过request预处理后,首先交由业务代码这边自行判断是否合法,是否需要处理错误,如果不合法,且自己不打算处理错误,则再抛出错误,这样的话,就符合很多后端框架的流程了,业务层的错误,先自己catch,要么处理,要么往框架抛,框架统一处理,流程大致如图:
改造后的request请求图

这样的话,所有的错误,业务层有了优先处理的权利,不需要自行处理的情况才交由框架做通用处理。
当然,在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方法内应该可以catchb方法抛出的错误

{
    methods:{
        async a(){
            this.b()
        },
        async b(){
            throw new Error("Error")
        }
    }
}