Vue Global Exception Handler Plugin

This week, I checked some articles about vue global exception handling, and I have made some modifications according to my own needs. I will record it here.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class ServiceError extends Error {
};

function isPromise(ret) {
return (ret && typeof ret.then = 'function' && typeof ret.catch = 'function');
}

function resetPageStatus(vm) {
if (vm.loading) {
vm.loading = false;
}
}

const errorHandler = (error, vm, info) => {
if (error instanceof ServiceError) {
vm.$_warning(error.message);
} else {
console.error(error);
}
const reset = vm.resetPageStatus || resetPageStatus;
reset(vm);
};

function registerActionHandle(actions) {
Object.keys(actions).forEach((key) => {
let fn = actions[key];
actions[key] = function (...args) {
let vm = this;
let ret = fn.apply(vm, args);
if (isPromise(ret)) {
return ret.catch(function(error) {
errorHandler(error, vm);
});
} else {//default error handling
return ret;
}
};
});
}
const registerVuex = (instance) => {
if (instance.$options['store']) {
let actions = instance.$options['store']['_actions'] || {};
if (actions) {
let tempActions = {};
Object.keys(actions).forEach((key) => {
tempActions[key] = actions[key][0];
});
registerActionHandle(tempActions);
}
}
};
const registerVue = (instance) => {
if (instance.$options.methods) {
let actions = instance.$options.methods || {};
if (actions) {
registerActionHandle(actions);
}
}
};

let GlobalError = {
install: (Vue, options) => {
Vue.prototype.ServiceError = Service Error;
Vue.config.errorHandler = errorHandler;
Vue.mixin({
beforeCreate() {
registerVue(this);
registerVuex(this);
}
});
Vue.prototype.$throw = errorHandler;
}
};

export default GlobalError;

Analysis

This global exception handling is just a preliminary template, mainly doing several things:

  • Customized new error type ServiceError.
  • Overrides Vue’s global exception handling interface (Vue.config.errorHandler), using the custom given errorHandler.
  • Before the component is loaded, use beforeCreate hook to traverse all methods. If it is a normal function, it will return directly. If it is a Promise function, call the custom errorHandler function in the catch function.

Through the above points, all exceptions that are not caught and handled by us will go to the errorHandler function.

So what does this errorHandler function do?

  • Determine whether it is our custom error type ServiceError, if so, pop up the ElementUI message component, the content is ServiceError errorMessage.
  • If it is a normal error, simply print it in Console.
  • Finally see if the page has a function to reset the state, if there is, then execute, otherwise execute the default state reset function, the current function is just to cancel the loading state.

How to use

1
2
3
4
//main.js
import Vue from 'vue';
import GlobalErrorCatchPlugin from './plugins/globalErrorCatchPlugin';
Vue.use(GlobalErrorCatchPlugin);

Summary

At present, it is just a relatively simple version, the purpose is just to not get the page stuck in the loading state if an uncaught exception occurs, and if it is a custom error, we can customize how to handle it.

If you communicate with the background through Axios, you can also declare the api as a method alone, so that once the whole method is 500, it will not affect the execution of the next function, such as:

The method that originally needed to be written like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async searchTableDataWithDateAndStatusByPage () {
this.loading = true;
this.gridData = [];
try {
const response = await EvtHubInboundMessageGW.qureyEvents(this.createSearchCondition(false));
if (response && response.status = 200) {
this.gridData = response.data;
} else {
throw new Error('refresh failed');
}
} catch (e) {
this.$_warning(this.$t('tips.refreshFailed'));
} finally {
this.loading = false;
}
},

It can be changed to this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async qureyEvents() {
return await EvtHubInboundMessageGW.qureyEvents(this.createSearchCondition(false));
}
async searchTableDataWithDateAndStatusByPage () {
this.loading = true;
this.gridData = [];
this.loading = true;
const response = await this.queryEvents();
if (response && response.status = 200) {
this.gridData = response.data;
} else {
this.$_warning(this.$t('tips.refreshFailed'));
}
this.loading = false;
},

This not only looks more comfortable, there are not so many Code Block nesting, but even if this. $_warning (this. $t (‘tips.refreshFailed’)); error occurs, the errorHandler will help us cancel the loading state.

In short, it is an attempt to catch vue global exceptions, which is still being improved.