preface
As a front-end, in the development process, even if very careful, full self-test, in the complex operation of different users will inevitably appear unexpected problems of programmers, to the company or individuals to bring huge losses. At this time, a front-end error monitoring system that can timely report errors and help programmers to solve errors is essential. Let’s talk about common errors and handling.
This paper mainly focuses on the following points:
- Common JS error types
- Common JS handling errors
- Report the way, and report the content of several thoughts
Question:
- JS, CSS, IMG and other resources loading failure (CDN or map bed hung, accidentally deleted, file name changed) how to real-time information? Instead of the user telling you?
- How can useful error information be reported so that programmers can quickly locate the error and fix it? Instead of reporting some confusing information?
- How to make good use of SourceMap file to deal with error information in today’s engineering of compressed ugly code?
- How to go wrong without having to ask the user to help you reproduce? Want to model? How to do it?
- How to make better statistics on the distribution of problems (models, devices, browsers, geographical locations, bandwidth, etc.) and independently choose compatibility tendencies according to the data?
- .
Common mistakes
- Script errors
- Grammar mistakes
- Runtime error
- Synchronization error
- Asynchronous error
- Promise error
- Network error
- Resource loading error
- Custom request error
You can read the monitoring library source code errorWatch for further understanding, or you can use it directly for projects.
Grammar mistakes
For example, English characters are written as Chinese characters. It is generally easy to discover during development.
Syntax errors cannot be handled by try catch
try {
const error = 'error';// semicolons with rounded corners
} catch(e) {
console.log('I can't sense a mistake');
}
Copy the code
Synchronization error
When executing a script, the JS engine pushes tasks into the event stack and polling them out for execution. Each event task has its own context. Any error occurred in the synchronized code executed in the current context can be caught by try catch to ensure that the subsequent synchronized code is executed.
try {
error
} catch(e) {
console.log(e);
}
Copy the code
Asynchronous error
Common methods such as setTimeout create new event tasks to insert into the event stack for later execution. So try catch cannot catch code errors in other contexts.
try {
setTimeout((a)= > {
error // Async error})}catch(e) {
console.log('I can't sense a mistake');
}
Copy the code
In order to analyze errors, the window.onerror event is used to listen for errors. It is more powerful than try catch’s ability to catch error messages.
/** * @param {String} MSG Error description * @param {String} URL error file * @param {Number} row Number * @param {Number} col Number * @param {Object} error Error Object */
window.onerror = function (msg, url, row, col, error) {
console.log('I know my mistake.');
// return true; // When true is returned, the exception will not be thrown up and the console will not print an error
};
Copy the code
- Window. onerror Precautions
window.onerror
Can catch common syntax, synchronous, asynchronous errors and other errors;window.onerror
Unable to capturePromise
Error, network error;window.onerror
Should be executed before all JS scripts to avoid omission;window.onerror
Easily overridden and should be considered when handling callbacks, being listened on by someone who is also using the event.
Network error
Because network request exceptions do not bubble, they need to be retrieved during the event capture phase. We can use window.addeventListener. For example, when important CDN resources such as code and pictures fail, it is extremely important to get timely feedback.
window.addEventListener('error', (error) => {
console.log('404 error');
console.log(error);
// return true; // Interrupts event propagation
}, true);
Copy the code
For such resource loading errors, sufficient information can be obtained in the event object, and the developer can be notified in the first time with SMS, nail, etc.
window.addEventListener('error', (e) => {
if(e.target ! = =window) { // Avoid duplicate reporting
console.log({
url: window.location.href, // Reference the resource address
srcUrl: e.target.src, // Resource loading error address})}},true);
Copy the code
window.onerror
与window.addEventListener
The benefit of window.addeventListener is that you can listen for multiple callbacks without overwriting them, but remember to destroy them to avoid memory leaks and errors. But you don’t get as much information as window.onerror. Generally, only window.addeventListener is used to monitor resource loading errors.
- You are advised to manually report customized network request errors.
Promise error
If you don’t catch a promise, then onError doesn’t do anything.
Promise.reject('promise error');
new Promise((resolve, reject) = > {
reject('promise error');
});
new Promise((resolve) = > {
resolve();
}).then((a)= > {
throw 'promise error';
});
Copy the code
You can use the same window. Onunhandledrejection or Windows. The addEventListener (” unhandledrejection “) to monitor the error. Receive a PromiseError object that resolves the Reason property of the error object, sort of like a stack.
The compatibility process can be seen in traceKit.js.
Report the way
img
reportajax
report
function report(errInfo) {
new Image().src = 'http://your-api-website? data=' + errInfo;
}
Copy the code
Ajax should be using a library, much the same.
- Note:
img
The request has a length limit. If the data is too large, it is best to use itajax.post
.
supplement
Script error
If a Script referencing a different domain name is not processed in a special way, an error is reported. For security reasons, browsers do not display a specific error, but a Script error. For example, if someone is quoting your online non-open source business code for ulterior motives, you don’t want them to know about your script error message.
How to solve the cross-domain error problem of own scripts?
- All resources are switched to the unified domain, but then lost
CDN
The advantage of. - In the script file
HTTP response header
Set in theCORS
.
Access-Control-Allow-Origin: You-allow-origin
;- Script tag
crossorigin
Properties, such as<script src="http://www.xxx.com/index.js" crossorigin></script>
Response header and Crossorigin values
crossorigin="anonymous"
(Default),CORS
Is not equal toYou-allow-origin
, can’tcookie
crossorigin="use-credentials"
andAccess-Control-Allow-Credentials: true
,CORS
Cannot be set to*
Can,cookie
. ifCORS
Is not equal toYou-allow-origin
The browser does not load JS.
Script errors can be filtered out and not reported when you cors free energy resources.
With all that said, there is a very important topic, how do I analyze error messages that I can catch?
JavaScript Error profiling
A JavaScript error usually consists of the following errors
- Error message
- Stack Trace
Developers can throw a JavaScript error in different ways:
- throw new Error(‘Problem description.’)
- throw Error(‘Problem description.’) <– equivalent to the first one
- throw ‘Problem description.’ <– bad
- throw null <– even worse
The second option is recommended; the third or fourth browsers cannot generate a trace stack for either of the two options.
If you can parse the error message in each row trace stack, the rows and columns in conjunction with SourceMap can locate each specific line of source code. The problem is that different browsers do not have a common format for this information. The difficulty lies in resolving compatibility issues.
For example, window.onerror the fifth parameter error object was added to the WHATWG specification in 2013. Safari and Internet Explorer 10 didn’t have them in the early days, Firefox added Error objects in version 14, and Chrome only added them in 2013.
The recommendation
-
Window. onerror is the best way to catch JS errors and is reported only when there is a valid Error object and trace stack. You can also avoid non-intrusive errors such as plug-in errors and cross-domain errors with incomplete information.
-
Try catch enhancements, which throw more complete error messages, can compensate for window.onerror. But as mentioned earlier, try catch does not catch asynchronous and promise errors, nor does it take advantage of V8 engine performance optimizations.
For example, Tencent’s BadJS has a try catch package for the following recommendations
- SetTimeout and setInterval
- event
- ajax callback
- Define and the require
- Main business entrance
Whether such a fine-grained package is needed depends on the situation.
SourceMap
For example, there is the following stack trace
ReferenceError: thisIsAbug is not defined
at Object.makeError (http://localhost:7001/public/js/traceKit.min.js:1:9435)
at http://localhost:7001/public/demo.html:28:12
Copy the code
Can be parsed into the following format
[{"args": []."url" : "http://localhost:7001/public/js/traceKit.min.js"."func" : "Object.makeError"."line" : 1."column" : 9435."context" : null
},
{
"args": []."url" : "http://localhost:7001/public/demo.html"."func" : "?"."line" : 28."column" : 12."context" : null}]Copy the code
With rows and columns and the corresponding SourceMap file, source code information can be parsed.
Analytical results
The processing code is as follows:
import { SourceMapConsumer } from 'source-map';
// Must be initialized
SourceMapConsumer.initialize({
'lib/mappings.wasm': 'https://unpkg.com/[email protected]/lib/mappings.wasm'});@param {String} rawSourceMap sourceMap * @param {Number} line error * @param {Number} Column compression code error column * @param {Number} offset set to return the Number of adjacent rows * @returns {Promise<{context: string, originLine: Number | null, source: string > | null}} * context: source lines error and fluctuation near offset, originLine: source line error, the source: the source file name * /
export const sourceMapDeal = async (rawSourceMap, line, column, offset) => {
// Convert to the sourceMapConsumer object using the sourceMap library
const consumer = await new SourceMapConsumer(rawSourceMap);
// Pass in the number of rows to find, find the source file before compression and the number of rows
const sm = consumer.originalPositionFor({
line, // The number of compressed lines
column, // The number of compressed columns
});
// A list of all source files before compression
const { sources } = consumer;
// Find the index position in the source file list
const smIndex = sources.indexOf(sm.source);
// Find the source code in the source list
const smContent = consumer.sourcesContent[smIndex];
// Split source code strings into arrays by "line end tag"
const rawLines = smContent.split(/\r? \n/g);
let begin = sm.line - offset;
const end = sm.line + offset + 1;
begin = begin < 0 ? 0 : begin;
const context = rawLines.slice(begin, end).join('\n');
// Remember to destroy
consumer.destroy();
return {
context,
originLine: sm.line + 1.// line starts at 0, so +1
source: sm.source,
}
};
Copy the code
You can easily understand this code based on the format of the SourceMap file.
Refer to the website
- mozilla/source-map
- Front-end code abnormal monitoring actual combat
- Front-end exception monitoring – BadJS
- Script error volume optimization – make the script error at a glance