Remember the process of finding a bug….

I’ve been busy all day. I’ve almost solved the bug. Look at the time, it’s already 5:30 p.m., think there’s still half an hour to do what?

Suddenly think of the task received two days ago: optimize the front-end error exception capture.

Just received this task, the brain’s first reaction: so easy! Window.onerror?

When I presented this solution, the leader continued, “This does capture, but we need to deal more with the degradation after the error.” (Timely identification of requirements is important)

Downgrade?

If window.onerror detects an error, it redirects to an error UI page. Six o ‘clock on the dot today should be a sure thing! Thought of here, can not help but start to drift!

However, the leader again suggested that this was not very friendly to users, we only need to degrade the component page that reported the error, and can not affect the access of other TAB bars or pages.

This……

Through a Google search, found this kind of problem many. The solutions are as follows:

  • try catch
  • Promise.catch
  • window.onerror
  • window.addEventListener(‘error’,cb)
  • .

It is true that there are a lot of discovery programs, but there are basically no true project requirements ~~

First of all, there are a lot of mistakes in the project. There are a lot of try catch/Promise words written in the project. Catch is obviously not very friendly, so I just give up. As for the window. The onerror/window. AddEventListener (‘ error ‘, cb) the two can be appropriate to consider.

After further investigation, window.onerror is not a panacea. When JS runtime errors occur, the window will raise an error event from the ErrorEvent interface and execute window.onerror().

/** * @param {String} message error message * @param {String} source error file * @param {Number} lineno line Number * @param {Number} colno column Number * @param {Object} error error Object (Object) */ window.onerror = function(message, source, lineno, colno, Error) {console.log(' caught exception: ',{message, source, lineno, colno, error}); }Copy the code

Through investigation, it is found that onError cannot catch syntax errors; And if it is a static resource exception, or an interface exception, the error cannot be caught. This is too pit dad….

Remember that in actual project development, there are a lot of chain operations on objects, such as:

Data type negotiated with the back end: data:{a:{b:c:{d}}}

When we want to get data D, we get it through data.a.B.C. D. As long as there is a problem in one of the links (the back end interface returns incorrect data or the interface is attacked and invalid, etc.), the online screen will be blank, which is very common.

Syntax errors cannot be caught by themselves; pass them.

Window. AddEventListener (‘error’,cb) ¶ If the listener fails to listen for HTTP requests, other resource loading failures and syntax errors can be detected.

Well, in that case, isn’t the problem solved? We use HTTP interceptor to listen for HTTP request errors, and then use window.addeventListener (‘error’,cb) to listen for other errors. Think about it and feel excited, feel almost off work!

However, as I got started, I remembered my original requirement to degrade the UI of the faulty component… How can this be achieved…. He was lost in thought again.

Downgrade? Huh? React does not officially have a downgrade instructions!

React NB

Error bounds cannot catch errors in the following scenarios:

  • Event Handling (learn more)
  • Asynchronous code (such as setTimeout or requestAnimationFrame callback)
  • Server side rendering
  • Errors thrown by itself (not by its children)

This is…

Event handling and asynchronous code can be captured using window.addeventListener (‘error’,cb). As for server rendering, it is not currently used, regardless of the error it throws. Directly copy your official component, I don’t believe can also make mistakes? The fork will waist!

Okay, now that the plan is set, start coding!

import React from 'react'; export interface IErrorBoundaryProps { children: object; } export interface IErrorBoundaryState { hasError: boolean; } export default class ErrorBoundary extends React.Component< IErrorBoundaryProps, IErrorBoundaryState > {static getDerivedStateFromError(error) {// Update state to enable the next rendering to display the degraded UI console.log(error); return { hasError: true }; } constructor(props) { super(props); this.state = { hasError: false }; } // componentDidCatch(error, errorInfo) {// // you can also print out error logs // console.log(error); // console.log(errorInfo); // } render() { console.log(this.state.hasError, 'this.state.hasError'); If (this.state-hasError) {// You can customize the degraded UI and render return <h1>Something went wrong.</h1>; } return this.props.children; }}Copy the code

If ErrorBoundary is nested in the routing component, it can degrade the routing page.

<Route key={item.path} path={item.path} render={(props) => ( <ErrorBoundary> <item.component {... props} routes={item.routes} /> </ErrorBoundary> )} />;Copy the code

All right! Test out getting ready to leave work!

Write a random error code in the component and see if it fires. However:

Why, what’s going on? It does achieve the desired effect, does not affect the use of other functions, but the UI, how different from what I expected?

Think hard, what’s the problem?

Overlay: {warnings: false, errors: true} in webpack configuration

No, if triggered by these two attributes, it will result in a full screen display, not just a route display. So what’s the problem?

The window.addeventListener (‘error’,cb) does not bubble into the window. Which ring is intercepted?

Through careful inspection, I found that the component that triggered the abnormality was covered with ErrorBoundary in a layer above, which did not arouse my alarm at the beginning, but after careful inspection, I found that

Could this be what’s causing it?

Remove this component and the custom error UI is displayed! Oh, my God! What a mistake!

But now it was dark, over ~~~

Summary: ErrorBoundary catches exceptions during rendering, window.addeventListener (‘error’, CB) catches exceptions for resources or other errors, HTTP interceptors catch request exceptions and make the whole project exceptions manageable.

There will be better plans and ideas to update later ~

Follow-up: juejin. Cn/post / 697956…