This article will discuss error handling in client-side JavaScript. Mainly introduces common mistakes, error handling, asynchronous code writing, etc. in JavaScript. Let's take a look at how to correctly handle errors in JavaScript
The event-driven paradigm of JavaScript adds a rich language and makes programming in JavaScript more diverse. If you think of the browser as an event-driven tool for JavaScript, then when an error occurs, an event will be thrown. It is theoretically possible to think that these errors are just simple events in JavaScript.
This article will discuss error handling in client-side JavaScript. Mainly introduces common mistakes, error handling, asynchronous code writing, etc. in JavaScript.
Let’s take a look at how to correctly handle errors in JavaScript.
Demo demonstration
The demo used in this article can be found on GitHub. After running, the page will look like this:
Each button will trigger an "Error (Exception)", and this error will simulate a thrown exception TypeError. The following is the definition of the module:
// scripts/error.js function error() { var foo = {}; return foo.bar(); }
First, this function declares an empty object foo. Note that bar() is not defined anywhere. Next, verify whether this unit test will raise an "error":
// tests/scripts/errorTest.js it('throws a TypeError', function () { should.throws(error, TypeError); });
This unit test is in Mocha and has a test declaration in Should.js. Mocha is the test runner tool and Should.js is the assertion library. This unit test runs on Node and does not require the use of a browser.
error() defines an empty object and then tries to access a method. Because bar() does not exist within the object, an exception will be thrown. This error that occurs in dynamic languages like JavaScript may happen to everyone!
Error handling (1)
Use the following code to handle the above error:
// scripts/badHandler.js function badHandler(fn) { try { return fn(); } catch (e) { } return null; }
The handler takes fn as an input parameter, and then fn will be called inside the handler function. The unit test will reflect the role of the above error handler:
// tests/scripts/badHandlerTest.js it('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); });
If a problem occurs, the error handler will return null. The fn() callback function can point to a legal method or error.
The following click events will continue event processing:
// 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));
This processing method hides an error in the code and is difficult to find. Hidden errors can take hours of debugging time. Especially in multi-layer solutions with deep call stacks, this error can be harder to find. So this is a very poor way of handling errors.
Error handling (2)
The following is another error handling method.
// scripts/uglyHandler.js function uglyHandler(fn) { try { return fn(); } catch (e) { throw new Error('a new error'); } }
The way to handle exceptions is as follows:
// tests/scripts/uglyHandlerTest.js it('returns a new error with errors', function () { var fn = function () { throw new TypeError('type error'); }; should.throws(function () { uglyHandler(fn); }, Error); });
The above has obvious improvements to the error handler . Here the exception will bubble up the call stack. At the same time, the error will expand the stack, which is very helpful for debugging. In addition to throwing an exception, the interpreter will look for additional processing along the stack. This also brings the possibility of handling errors from the top of the stack. But this is still poor error handling, requiring us to trace the original exception step by step down the stack.
An alternative can be adopted to end this poor error handling with a custom error method. This approach becomes helpful as you add more details to the error.
For example:
// scripts/specifiedError.js // Create a custom error var 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.js function uglyHandlerImproved(fn) { try { return fn(); } catch (e) { throw new SpecifiedError(e.message); } } // tests/scripts/uglyHandlerImprovedTest.js it('returns a specified error with errors', function () { var fn = function () { throw new TypeError('type error'); }; should.throws(function () { uglyHandlerImproved(fn); }, SpecifiedError); });
The specified error adds more details and preserves the original error message. With this improvement, the above processing is no longer a poor processing method, but a clear and useful method.
After the above processing, we also received an unhandled exception. Next let's look at how browsers can help when handling errors.
Expand the stack
One way to handle exceptions is to add try...catch at the top of the call stack.
For example:
function main(bomb) { try { bomb(); } catch (e) { // Handle all the error things } }
However, the browser is event-driven, and exceptions in JavaScript are also events. When an exception occurs, the interpreter pauses execution and unwinds:
// scripts/errorHandlerDom.js window.addEventListener('error', function (e) { var error = e.error; console.log(error); });
This event handler catches any errors that occur in the execution context. Error events occurring on various targets can trigger various types of errors. This centralized error handling in the code is very aggressive. You can use daisy chaining to handle specific errors. If you follow SOLID principles, you can use error handling with a single purpose. These handlers can be registered at any time, and the interpreter will loop through the handlers that need to be executed. The code base can be released from the try...catch block, which also makes debugging easy. In JavaScript, it's important to treat error handling as event handling.
捕获堆栈
在解决问题时,调用堆栈会非常有用,同时浏览器正好可以提供这些信息。虽然堆栈属性不是标准的一部分,但是最新的浏览器已经可以查看这些信息了。
下面是在服务器上记录错误的示例:
// scripts/errorAjaxHandlerDom.js window.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 details xhr.send(message); });
每个错误处理都具有单个目的,这样可以保持代码的DRY原则(目的单一,不要重复自己原则)。
在浏览器中,需要将事件处理添加到DOM。这意味着如果你正在构建第三方库,那么你的事件会与客户端代码共存。window.addEventListener( )会帮你进行处理,同时也不会抹去现有的事件。
这是服务器上日志的截图:
可以通过命令提示符查看日志,但是Windows上,日志是非动态的。
通过日志可以清楚的看到,具体什么情况触发了什么错误。在调试时调用堆栈也会非常有用,所以不要低估调用堆栈的作用。
在JavaScript中,错误信息仅适用于单个域。因为在使用来自不用域的脚本时,将会看不到任何错误详细信息。
一种解决方案是重新抛出错误,同时保留错误消息:
一旦重新启动了错误备
try { return fn(); } catch (e) { throw new Error(e.message); }
份,全局错误处理程序就会完成其余的工作。确保你的错误处理处在相同域中,这样会保留原始消息,堆栈和自定义错误对象。
异步处理
JavaScript在运行异步代码时,进行下面的异常处理,会产生一个问题:
// scripts/asyncHandler.js function asyncHandler(fn) { try { // This rips the potential bomb from the current context setTimeout(function () { fn(); }, 1); } catch (e) { } }
通过单元测试来查看问题:
// tests/scripts/asyncHandlerTest.js it('does not catch exceptions with errors', function () { // The bomb var fn = function () { throw new TypeError('type error'); }; // Check that the exception is not caught should.doesNotThrow(function () { asyncHandler(fn); }); });
这个异常没有被捕获,我们通过单元测试来验证。尽管代码包含了try...catch,但是try...catch语句只能在单个执行上下文中工作。当异常被抛出时,解释器已经脱离了try...catch,所以异常未被处理。Ajax调用也会发生同样的情况。
所以,一种解决方案是在异步回调中捕获异常:
setTimeout(function () { try { fn(); } catch (e) { // Handle this async error } }, 1);
这种做法会比较奏效,但仍有很大的改进空间。
首先,这些try...catch block在整个区域纠缠不清。事实上,V8浏览器引擎不鼓励在函数内使用try ... catch block。V8是Chrome浏览器和Node中使用的JavaScript引擎。一种做法是将try...catch block移动到调用堆栈的顶部,但这却不适用于异步代码编程。
由于全局错误处理可以在任何上下文中执行,所以如果为错误处理添加一个窗口对象,那么就能保证代码的DRY和SOLID原则。同时全局错误处理也能保证你的异步代码很干净。
以下是该异常处理在服务器上的报告内容。请注意,输出内容会根据浏览器的不同而不同。
从错误处理中可以看到,错误来自于异步代码的setTimeout( )功能。
结论
在进行错误处理时,不要隐藏问题,而应该及时发现问题,并采用各种方法追溯问题的根源以便解决问题。虽然编写代码时,时常难免会埋下错误,但是我们也无须为错误的发生过于感到羞愧,及时解决发现问题从而避免更大的问题发生,正是我们现在需要做的。
总结
The above is the detailed content of Summary of correct error handling in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

The main difference between Python and JavaScript is the type system and application scenarios. 1. Python uses dynamic types, suitable for scientific computing and data analysis. 2. JavaScript adopts weak types and is widely used in front-end and full-stack development. The two have their own advantages in asynchronous programming and performance optimization, and should be decided according to project requirements when choosing.

Whether to choose Python or JavaScript depends on the project type: 1) Choose Python for data science and automation tasks; 2) Choose JavaScript for front-end and full-stack development. Python is favored for its powerful library in data processing and automation, while JavaScript is indispensable for its advantages in web interaction and full-stack development.

Python and JavaScript each have their own advantages, and the choice depends on project needs and personal preferences. 1. Python is easy to learn, with concise syntax, suitable for data science and back-end development, but has a slow execution speed. 2. JavaScript is everywhere in front-end development and has strong asynchronous programming capabilities. Node.js makes it suitable for full-stack development, but the syntax may be complex and error-prone.

JavaScriptisnotbuiltonCorC ;it'saninterpretedlanguagethatrunsonenginesoftenwritteninC .1)JavaScriptwasdesignedasalightweight,interpretedlanguageforwebbrowsers.2)EnginesevolvedfromsimpleinterpreterstoJITcompilers,typicallyinC ,improvingperformance.

JavaScript can be used for front-end and back-end development. The front-end enhances the user experience through DOM operations, and the back-end handles server tasks through Node.js. 1. Front-end example: Change the content of the web page text. 2. Backend example: Create a Node.js server.

Choosing Python or JavaScript should be based on career development, learning curve and ecosystem: 1) Career development: Python is suitable for data science and back-end development, while JavaScript is suitable for front-end and full-stack development. 2) Learning curve: Python syntax is concise and suitable for beginners; JavaScript syntax is flexible. 3) Ecosystem: Python has rich scientific computing libraries, and JavaScript has a powerful front-end framework.

The power of the JavaScript framework lies in simplifying development, improving user experience and application performance. When choosing a framework, consider: 1. Project size and complexity, 2. Team experience, 3. Ecosystem and community support.

Introduction I know you may find it strange, what exactly does JavaScript, C and browser have to do? They seem to be unrelated, but in fact, they play a very important role in modern web development. Today we will discuss the close connection between these three. Through this article, you will learn how JavaScript runs in the browser, the role of C in the browser engine, and how they work together to drive rendering and interaction of web pages. We all know the relationship between JavaScript and browser. JavaScript is the core language of front-end development. It runs directly in the browser, making web pages vivid and interesting. Have you ever wondered why JavaScr


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment

Atom editor mac version download
The most popular open source editor

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.
