Programmers will definitely encounter errors when writing programs. This article is based on the concept of error handling in JavaScript. I hope it will help you when you write JavaScript programs.
Demo Demonstration
The Demo we use can be downloaded from GitHub. When the program is run, the following page will appear:
All buttons will trigger errors and throw TypeError. The following is the definition of the module:
// scripts/error.jsfunction error() {var foo = {};return foo.bar();}
An empty object foo is defined in error(), so calling foo.bar() will cause it to be undefined And report an error. Let’s use unit testing to verify:
// tests/scripts/errorTest.jsit('throws a TypeError', function () {should.throws(error, TypeError);});
We use Mocha with Should.js for unit testing.
After you clone the code base and install the dependency packages, you can use npm t to execute tests. Of course, you can also execute a test file, such as: ./node_modules/mocha/bin/mocha tests/scripts/errorTest.js
Believe me, for a dynamic language like JavaScript, no matter who It's easy to encounter errors like this.
Bad handling method
I have abstracted the event processing function corresponding to the button a little simpler, as follows:
// scripts/badHandler.jsfunction badHandler(fn) {try {return fn();} catch (e) { }return null;}
badHandler receives an fn as a callback function, the callback function is called in badHandler. We write the corresponding unit test:
// tests/scripts/badHandlerTest.jsit('returns a value without errors', function() {var fn = function() {return 1;};var result = badHandler(fn);result.should.equal(1);});it('returns a null with errors', function() {var fn = function() {throw new Error('random error');};var result = badHandler(fn);should(result).equal(null);});
You will find that if an exception occurs, badHandler simply returns null. If you match the complete code, you will find the problem:
// scripts/badHandlerDom.js(function (handler, bomb) {var badButton = document.getElementById('bad'); if (badButton) {badButton.addEventListener('click', function () {handler(bomb);console.log('Imagine, getting promoted for hiding mistakes');}); }}(badHandler, error));
If you try-catch it when an error occurs, and then just return null, I can't find what went wrong at all. This fail-silent strategy may lead to UI confusion and data confusion, and you may spend several hours debugging but ignore the code in try-catch, which is the source of the disaster. If the code is so complex that it has multiple levels of calls, it will be almost impossible to find what went wrong. Therefore, we do not recommend using the silent failure strategy, we need a more elegant approach.
Not bad but bad way
// scripts/uglyHandler.jsfunction uglyHandler(fn) {try {return fn();} catch (e) {throw new Error('a new error');}}
The way it handles errors is to catch error e and then throw a new error. This is indeed better than the previous strategy of quiet failure. If something goes wrong, I can go back layer by layer until I find the error e that was originally thrown. Simply throwing an Error ('a new error') has limited information and is not accurate. We customize the error object and send out more information:
// scripts/specifiedError.js// Create a custom errorvar SpecifiedError = function SpecifiedError(message) {this.name = 'SpecifiedError';this.message = message || '';this.stack = (new Error()).stack;}; SpecifiedError.prototype = new Error();SpecifiedError.prototype.constructor = SpecifiedError; 、// scripts/uglyHandlerImproved.jsfunction uglyHandlerImproved(fn) {try {return fn();} catch (e) {throw new SpecifiedError(e.message);}}// tests/scripts/uglyHandlerImprovedTest.jsit('returns a specified error with errors', function () {var fn = function () {throw new TypeError('type error');};should.throws(function () {uglyHandlerImproved(fn);}, SpecifiedError);});
Now , this custom error object contains the original error information and therefore becomes more useful. But because it was thrown again, it was still an unhandled error.
Interception of exceptions
One idea is to surround all functions with try...catch:
function main(bomb) {try {bomb();} catch (e) {// Handle all the error things}}
However, such code will become very Bloated, unreadable, and inefficient. Do you still remember? At the beginning of this article, we mentioned that an exception in JavaScript is just an event. Fortunately, there is a global exception event handling method (onerror).
// scripts/errorHandlerDom.jswindow.addEventListener('error', function (e) {var error = e.error;console.log(error);});
Get stack information
You can send error information to the server:
// scripts/errorAjaxHandlerDom.jswindow.addEventListener('error', function (e) {var stack = e.error.stack;var message = e.error.toString();if (stack) {message += '\n' + stack;} var xhr = new XMLHttpRequest();xhr.open('POST', '/log', true);// Fire an Ajax request with error detailsxhr.send(message);});
In order to obtain more detailed error information and save the trouble of processing data , you can also use fundebug's JavaScript monitoring plug-in to quickly access the bug monitoring service in three minutes.
The following is the error message received by the server:
If your script is placed under another domain name, if you do not enable CORS, in addition to Script error., you will not see any useful error information. If you want to know the specific solution, please refer to: Script error. Comprehensive analysis.
Asynchronous error handling
Since setTimeout is executed asynchronously, the following code exception will not be caught by try...catch:
// scripts/asyncHandler.jsfunction asyncHandler(fn) {try {// This rips the potential bomb from the current contextsetTimeout(function () {fn();}, 1);} catch (e) { }}
The try...catch statement will only capture exceptions in the current execution environment. But when the above exception is thrown, the JavaScript interpreter is no longer in try...catch, so it cannot be caught. The same goes for all Ajax requests.
We can make a slight improvement and write try...catch into the callback of the asynchronous function:
setTimeout(function () {try {fn();} catch (e) {// Handle this async error}}, 1);
However, such a routine will cause the project to It is full of try...catch, and the code is not concise. Also, the V8 engine that executes JavaScript discourages the use of try...catch in functions. Fortunately, we don't need to do this, the global error handling onerror will catch these errors.
in conclusion
My advice is don't hide errors, be brave enough to throw them out. No one should be ashamed because a bug in the code causes the program to crash. We can interrupt the program and let the user start over. Mistakes are inevitable, how you deal with them is what matters.
The above content is how to deal with JavaScript errors. If you find it useful, please quickly collect it.
Related recommendations:
Perfect solution to PHP installation Implementation steps and error reporting of extending mysqli
MySQL database error: Solution to Too many connections
The above is the detailed content of How to handle JavaScript exceptions. For more information, please follow other related articles on the PHP Chinese website!