Better Error Handling In NodeJS With Error Classes — Smashing Magazine (2023)

  • Kelvin Omereshone
  • 0 comments
  • 21 min read
  • JavaScript,Node.js,Apps

About The Author

Kelvin is an independent software maker currently building Sailscasts — a platform to learn server-side JavaScript. He is also a technical writer and …More aboutKelvin↬

Email Newsletter

.
Trusted by 200,000+ folks.

    This article is for JavaScript and NodeJS developers who want to improve error-handling in their applications. Kelvin Omereshone explains the error class pattern and how to use it for a better, more efficient way of handling errors across your applications.

    Error handling is one of those parts of software development that don’t quite get the amount of attention it really deserves. However, building robust applications requires dealing with errors properly.

    You can get by in NodeJS without properly handling errors but due to the asynchronous nature of NodeJS, improper handling or errors can cause you pain soon enough — especially when debugging applications.

    Before we proceed, I would like to point out the type of errors we’ll be discussing how to utilize error classes.

    Operational Errors

    These are errors discovered during the run time of a program. Operational errors are not bugs and can occur from time to time mostly because of one or a combination of several external factors like a database server timing out or a user deciding to make an attempt on SQL injection by entering SQL queries in an input field.

    Below are more examples of operational errors:

    • Failed to connect to a database server;
    • Invalid inputs by the user (server responds with a 400 response code);
    • Request timeout;
    • Resource not found (server responds with a 404 response code);
    • Server returns with a 500 response.

    It’s also worthy of note to briefly discuss the counterpart of Operational Errors.

    Programmer Errors

    These are bugs in the program which can be resolved by changing the code. These types of errors can not be handled because they occur as a result of the code being broken. Example of these errors are:

    • Trying to read a property on an object that is not defined.
     const user = { firstName: 'Kelvin', lastName: 'Omereshone', } console.log(user.fullName) // throws 'undefined' because the property fullName is not defined
    • Invoking or calling an asynchronous function without a callback.
    • Passing a string where a number was expected.

    This article is about Operational Error handling in NodeJS. Error handling in NodeJS is significantly different from error handling in other languages. This is due to the asynchronous nature of JavaScript and the openness of JavaScript with errors. Let me explain:

    (Video) try, catch, finally, throw - error handling in JavaScript

    In JavaScript, instances of the error class is not the only thing you can throw. You can literally throw any data type this openness is not allowed by other languages.

    For example, a JavaScript developer may decide to throw in a number instead of an error object instance, like so:

    // badthrow 'Whoops :)';// goodthrow new Error('Whoops :)')

    You might not see the problem in throwing other data types, but doing so will result in a harder time debugging because you won’t get a stack trace and other properties that the Error object exposes which are needed for debugging.

    Let’s look at some incorrect patterns in error handling, before taking a look at the Error class pattern and how it is a much better way for error handling in NodeJS.

    More after jump! Continue reading below↓

    Bad Error Handling Pattern #1: Wrong Use Of Callbacks

    Real-world scenario: Your code depends on an external API requiring a callback to get the result you expect it to return.

    Let’s take the below code snippet:

    'use strict';const fs = require('fs');const write = function () { fs.mkdir('./writeFolder'); fs.writeFile('./writeFolder/foobar.txt', 'Hello World');}write();

    Until NodeJS 8 and above, the above code was legitimate, and developers would simply fire and forget commands. This means developers weren’t required to provide a callback to such function calls, and therefore could leave out error handling. What happens when the writeFolder hasn’t been created? The call to writeFile won’t be made and we wouldn’t know anything about it. This might also result in race condition because the first command might not have finished when the second command started again, you wouldn’t know.

    Let’s start solving this problem by solving the race condition. We would do so by giving a callback to the first command mkdir to ensure the directory indeed exists before writing to it with the second command. So our code would look like the one below:

    'use strict';const fs = require('fs');const write = function () { fs.mkdir('./writeFolder', () => { fs.writeFile('./writeFolder/foobar.txt', 'Hello World!'); });}write();

    Though we solved the race condition, we are not done quite yet. Our code is still problematic because even though we used a callback for the first command, we have no way of knowing if the folder writeFolder was created or not. If the folder wasn’t created, then the second call will fail again but still, we ignored the error yet again. We solve this by…

    Error Handling With Callbacks

    In order to handle error properly with callbacks, you must make sure you always use the error-first approach. What this means is that you should first check if there is an error returned from the function before going ahead to use whatever data(if any) was returned. Let’s see the wrong way of doing this:

    'use strict';// Wrongconst fs = require('fs');const write = function (callback) { fs.mkdir('./writeFolder', (err, data) => { if (data) fs.writeFile('./writeFolder/foobar.txt', 'Hello World!'); else callback(err) });}write(console.log);

    The above pattern is wrong because sometimes the API you are calling might not return any value or might return a falsy value as a valid return value. This would make you end up in an error case even though you might apparently have a successful call of the function or API.

    The above pattern is also bad because it’s usage would eat up your error(your errors won’t be called even though it might have happened). You will also have no idea of what is happening in your code as a result of this kind of error handling pattern. So the right way for the above code would be:

    'use strict';// Rightconst fs = require('fs');const write = function (callback) { fs.mkdir('./writeFolder', (err, data) => { if (err) return callback(err) fs.writeFile('./writeFolder/foobar.txt', 'Hello World!'); });}write(console.log);

    Wrong Error Handling Pattern #2: Wrong Use Of Promises

    Real-world scenario: So you discovered Promises and you think they are way better than callbacks because of callback hell and you decided on promisifying some external API your code base depended upon. Or you are consuming a promise from an external API or a browser API like the fetch() function.

    These days we don’t really use callbacks in our NodeJS codebases, we use promises. So let’s reimplement our example code with a promise:

    'use strict';const fs = require('fs').promises;const write = function () { return fs.mkdir('./writeFolder').then(() => { fs.writeFile('./writeFolder/foobar.txt', 'Hello world!') }).catch((err) => { // catch all potential errors console.error(err) })}

    Let’s put the above code under a microscope — we can see that we are branching off the fs.mkdir promise into another promise chain(the call to fs.writeFile) without even handling that promise call. You might think a better way to do it would be:

    'use strict';const fs = require('fs').promises;const write = function () { return fs.mkdir('./writeFolder').then(() => { fs.writeFile('./writeFolder/foobar.txt', 'Hello world!').then(() => { // do something }).catch((err) => { console.error(err); }) }).catch((err) => { // catch all potential errors console.error(err) })}

    But the above would not scale. This is because if we have more promise chain to call, we would end up with something similar to the callback hell which promises were made to solve. This means our code will keep indenting to the right. We would have a promise hell on our hands.

    Promisifying A Callback-Based API

    Most times you would want to promisify a callback-based API on your own in order to better handle errors on that API. However, this is not really easy to do. Let’s take an example below to explain why.

    function doesWillNotAlwaysSettle(arg) { return new Promise((resolve, reject) => { doATask(foo, (err) => { if (err) { return reject(err); } if (arg === true) { resolve('I am Done') } }); });}

    From the above, if arg is not true and we don’t have an error from the call to the doATask function then this promise will just hang out which is a memory leak in your application.

    (Video) Smashing TV: "Technical SEO for Single Page Apps" with Martin Splitt (Oct 8, 2019)

    Swallowed Sync Errors In Promises

    Using the Promise constructor has several difficulties one of these difficulties is; as soon as it is either resolved or rejected it cannot get another state. This is because a promise can only get a single state — either it is pending or it is resolved/rejected. This means we can have dead zones in our promises. Let’s see this in code:

    function deadZonePromise(arg) { return new Promise((resolve, reject) => { doATask(foo, (err) => { resolve('I’m all Done'); throw new Error('I am never reached') // Dead Zone }); });}

    From the above we see as soon as the promise is resolved, the next line is a dead zone and will never be reached. This means any following synchronous error handling perform in your promises will just be swallowed and will never be thrown.

    Real-World Examples

    The examples above help explain poor error handling patterns, let’s take a look at the sort of problems you might see in real-life.

    Real World Example #1 — Transforming Error To String

    Scenario: You decided the error returned from an API is not really good enough for you so you decided to add your own message to it.

    'use strict';function readTemplate() { return new Promise(() => { databaseGet('query', function(err, data) { if (err) { reject('Template not found. Error: ', + err); } else { resolve(data); } }); });}readTemplate();

    Let’s look at what is wrong with the above code. From the above we see the developer is trying to improve the error thrown by the databaseGet API by concatenating the returned error with the string “Template not found”. This approach has a lot of downsides because when the concatenation was done, the developer implicitly runs toString on the error object returned. This way he loses any extra information returned by the error(say goodbye to stack trace). So what the developer has right now is just a string that is not useful when debugging.

    A better way is to keep the error as it is or wrap it in another error that you’ve created and attached the thrown error from the databaseGet call as a property to it.

    Real-World Example #2: Completely Ignoring The Error

    Scenario: Perhaps when a user is signing up in your application, if an error occur you want to just catch the error and show a custom message but you completely ignored the error that was caught without even logging it for debugging purposes.

    router.get('/:id', function (req, res, next) { database.getData(req.params.userId) .then(function (data) { if (data.length) { res.status(200).json(data); } else { res.status(404).end(); } }) .catch(() => { log.error('db.rest/get: could not get data: ', req.params.userId); res.status(500).json({error: 'Internal server error'}); })});

    From the above, we can see that the error is completely ignored and the code is sending 500 to the user if the call to the database failed. But in reality, the cause for the database failure might be malformed data sent by the user which is an error with the status code of 400.

    In the above case, we would be ending up in a debugging horror because you as the developer wouldn’t know what went wrong. The user won’t be able to give a decent report because 500 internal server error is always thrown. You would end up wasting hours in finding the problem which will tantamount to wastage of your employer’s time and money.

    Real-World Example #3: Not Accepting The Error Thrown From An API

    Scenario: An error was thrown from an API you were using but you don’t accept that error instead you marshall and transform the error in ways that make it useless for debugging purposes.

    Take the following code example below:

    async function doThings(input) { try { validate(input); try { await db.create(input); } catch (error) { error.message = `Inner error: ${error.message}` if (error instanceof Klass) { error.isKlass = true; } throw error } } catch (error) { error.message = `Could not do things: ${error.message}`; await rollback(input); throw error; }}

    A lot is going on in the above code that would lead to debugging horror. Let’s take a look:

    • Wrapping try/catch blocks: You can see from the above that we are wrapping try/catch block which is a very bad idea. We normally try to reduce the use of try/catch blocks to minify the surface where we would have to handle our error (think of it as DRY error handling);
    • We are also manipulating the error message in the attempt to improve which is also not a good idea;
    • We are checking if the error is an instance of type Klass and in this case, we are setting a boolean property of the error isKlass to truev(but if that check passes then the error is of the type Klass);
    • We are also rolling back the database too early because, from the code structure, there is a high tendency that we might not have even hit the database when the error was thrown.

    Below is a better way to write the above code:

    async function doThings(input) { validate(input); try { await db.create(input); } catch (error) { try { await rollback(); } catch (error) { logger.log('Rollback failed', error, 'input:', input); } throw error; }}

    Let’s analyze what we are doing right in the above snippet:

    • We are using one try/catch block and only in the catch block are we using another try/catch block which is to serve as a guard in case something goes on with that rollback function and we are logging that;
    • Finally, we are throwing our original received error meaning we don’t lose the message included in that error.

    Testing

    We mostly want to test our code(either manually or automatically). But most times we are only testing for the positive things. For a robust test, you must also test for errors and edge cases. This negligence is responsible for bugs finding their way into production which would cost more extra debugging time.

    Tip: Always make sure to test not only the positive things(getting a status code of 200 from an endpoint) but also all the error cases and all the edge cases as well.

    Real-World Example #4: Unhandled Rejections

    If you’ve used promises before, you have probably run into unhandled rejections.

    Here is a quick primer on unhandled rejections. Unhandled rejections are promise rejections that weren’t handled. This means that the promise was rejected but your code will continue running.

    Let’s look at a common real-world example that leads to unhandled rejections..

    'use strict';async function foobar() { throw new Error('foobar');}async function baz() { throw new Error('baz')}(async function doThings() { const a = foobar(); const b = baz(); try { await a; await b; } catch (error) { // ignore all errors! }})();

    The above code at first look might seem not error-prone. But on a closer look, we begin to see a defect. Let me explain: What happens when a is rejected? That means await b is never reached and that means its an unhandled rejection. A possible solution is to use Promise.all on both promises. So the code would read like so:

    'use strict';async function foobar() { throw new Error('foobar');}async function baz() { throw new Error('baz')}(async function doThings() { const a = foobar(); const b = baz(); try { await Promise.all([a, b]); } catch (error) { // ignore all errors! }})();

    Here is another real-world scenario that would lead to an unhandled promise rejection error:

    (Video) Roman Kuba - Rocking static sites with Nuxt, Vue and Node

    'use strict';async function foobar() { throw new Error('foobar');}async function doThings() { try { return foobar() } catch { // ignoring errors again ! }}doThings();

    If you run the above code snippet, you will get an unhandled promise rejection, and here is why: Although it’s not obvious, we are returning a promise (foobar) before we are handling it with the try/catch. What we should do is await the promise we are handling with the try/catch so the code would read:

    'use strict';async function foobar() { throw new Error('foobar');}async function doThings() { try { return await foobar() } catch { // ignoring errors again ! }}doThings();

    Wrapping Up On The Negative Things

    Now that you have seen wrong error handling patterns, and possible fixes, let’s now dive into Error class pattern and how it solves the problem of wrong error handling in NodeJS.

    Error Classes

    In this pattern, we would start our application with an ApplicationError class this way we know all errors in our applications that we explicitly throw are going to inherit from it. So we would start off with the following error classes:

    • ApplicationError
      This is the ancestor of all other error classes i.e all other error classes inherits from it.
    • DatabaseError
      Any error relating to Database operations will inherit from this class.
    • UserFacingError
      Any error produced as a result of a user interacting with the application would be inherited from this class.

    Here is how our error class file would look like:

    'use strict';// Here is the base error classes to extend fromclass ApplicationError extends Error { get name() { return this.constructor.name; }}class DatabaseError extends ApplicationError { }class UserFacingError extends ApplicationError { }module.exports = { ApplicationError, DatabaseError, UserFacingError}

    This approach enables us to distinguish the errors thrown by our application. So now if we want to handle a bad request error (invalid user input) or a not found error (resource not found) we can inherit from the base class which is UserFacingError (as in the code below).

    const { UserFacingError } = require('./baseErrors')class BadRequestError extends UserFacingError { constructor(message, options = {}) { super(message); // You can attach relevant information to the error instance // (e.g.. the username) for (const [key, value] of Object.entries(options)) { this[key] = value; } } get statusCode() { return 400; }}class NotFoundError extends UserFacingError { constructor(message, options = {}) { super(message); // You can attach relevant information to the error instance // (e.g.. the username) for (const [key, value] of Object.entries(options)) { this[key] = value; } } get statusCode() { return 404 }}module.exports = { BadRequestError, NotFoundError}

    One of the benefits of the error class approach is that if we throw one of these errors, for example, a NotFoundError, every developer reading this codebase would be able to understand what is going on at this point in time(if they read the code).

    You would be able to pass in multiple properties specific to each error class as well during the instantiation of that error.

    Another key benefit is that you can have properties that are always part of an error class, for example, if you receive a UserFacing error, you would know that a statusCode is always part of this error class now you can just directly use it in the code later on.

    Tips On Utilizing Error Classes

    • Make your own module(possibly a private one) for each error class that way you can simply import that in your application and use it everywhere.
    • Throw only errors that you care about(errors that are instances of your error classes). This way you know your error classes are your only Source of Truth and it contains all information necessary to debug your application.
    • Having an abstract error module is quite useful because now we know all necessary information concerning errors our applications can throw are in one place.
    • Handle errors in layers. If you handle errors everywhere, you have an inconsistent approach to error handling which is hard to keep track of. By layers I mean like database, express/fastify/HTTP layers, and so on.

    Let’s see how error classes looks in code. Here is an example in express:

    const { DatabaseError } = require('./error')const { NotFoundError } = require('./userFacingErrors')const { UserFacingError } = require('./error')// Expressapp.get('/:id', async function (req, res, next) { let data try { data = await database.getData(req.params.userId) } catch (err) { return next(err); } if (!data.length) { return next(new NotFoundError('Dataset not found')); } res.status(200).json(data)})app.use(function (err, req, res, next) { if (err instanceof UserFacingError) { res.sendStatus(err.statusCode); // or res.status(err.statusCode).send(err.errorCode) } else { res.sendStatus(500) } // do your logic logger.error(err, 'Parameters: ', req.params, 'User data: ', req.user)});

    From the above, we are leveraging that Express exposes a global error handler which allows you handle all your errors in one place. You can see the call to next() in the places we are handling errors. This call would pass the errors to the handler which is defined in the app.use section. Because express does not support async/await we are using try/catch blocks.

    So from the above code, to handle our errors we just need to check if the error that was thrown is a UserFacingError instance and automatically we know that there would be a statusCode in the error object and we send that to the user (you might want to have a specific error code as well which you can pass to the client) and that is pretty much it.

    You would also notice that in this pattern (error class pattern) every other error that you did not explicitly throw is a 500 error because it is something unexpected that means you did not explicitly throw that error in your application. This way, we are able to distinguish the types of error going on in our applications.

    Conclusion

    Proper error handling in your application can make you sleep better at night and save debug time. Here are some takeaway key points to take from this article:

    • Use error classes specifically set up for your application;
    • Implement abstract error handlers;
    • Always use async/await;
    • Make errors expressive;
    • User promisify if necessary;
    • Return proper error statuses and codes;
    • Make use of promise hooks.

    .nl-boxform .nl-boxform–button,.nl-boxform .nl-boxform–email{flex-grow:1;flex-shrink:0;box-sizing:border-box;width:auto;margin:0;padding:.75em 1em;border:0;border-radius:11px;background:#fff;font-size:1em}

    input.nl-boxform–email:active,input.nl-boxform–email:focus,.nl-boxform–button:active,.nl-boxform–button:focus{box-shadow:0 1px 1px rgba(0,0,0,.3)}

    .nl-boxform–button:-ms-input-placeholder,.nl-boxform–email:-ms-input-placeholder{color:#777;font-style:italic}

    .nl-boxform–email::placeholder,.nl-boxform–button::placeholder{color:#777;font-style:italic}

    .nl-boxform .nl-boxform–button{transition:all .2s ease-in-out;color:#fff;background-color:#0168b8;font-family:Mija,-apple-system,Arial,BlinkMacSystemFont,“roboto Slab”, “droid Serif”, “segoe UI”, Ubuntu, Cantarell, Georgia, serif;font-weight:700;box-shadow:0 1px 1px rgba(0,0,0,.3);width:100%;border:0;border-left:1px solid #ddd;flex:2;border-top-left-radius:0;border-bottom-left-radius:0}

    .nl-boxform .nl-boxform–email{border-top-right-radius:0;border-bottom-right-radius:0;width:100%;flex:4}

    .nl-box__img{height:auto;width:100%}

    @media all and (max-width: 650px){.nl-boxform .nl-boxgroup { flex-wrap: wrap; box-shadow: none; } .nl-boxform .nl-boxform–email, .nl-boxform .nl-boxform–button { border-radius: 11px; border-left: none; }

    .cardsgrid { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } .nl-boxform .nl-boxform–email { box-shadow: 0 13px 27px -5px rgba(50, 50, 93, 0.25), 0 8px 16px -8px rgba(0, 0, 0, 0.3), 0 -6px 16px -6px rgba(0, 0, 0, 0.025); min-width: 100%; } .nl-boxform .nl-box__form–button { margin-top: 1em; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5); }}

    .nl-boxform .nl-boxform–button:active,.nl-boxform .nl-boxform–button:focus,.nl-boxform .nl-boxform–button:hover{cursor:pointer;color:#fff;background-color:#0168b8;border-color:#dadada;box-shadow:0 1px 1px rgba(0,0,0,.3)}

    (Video) Building Websites with the CMS for Laravel - Statamic! Building websites has become too easy! #2

    .nl-boxform .nl-boxform–button:focus,.nl-boxform .nl-boxform–button:active{outline:none!important;text-shadow:1px 1px 1px rgba(0,0,0,.3);box-shadow:inset 0 3px 3px rgba(0,0,0,.3)}

    .nl-box__group{display:flex;box-shadow:0 13px 27px -5px rgba(50,50,93,.25),0 8px 16px -8px rgba(0,0,0,.3),0 -6px 16px -6px rgba(0,0,0,.025);border-radius:11px}

    .nl-box__wrapper{display:flex;flex-direction:column;justify-content:center}

    .nl-box__form form{width:100%}

    .nl-boxform .nl-boxgroup{margin:0}

    .nl-box__caption{font-size:.9em;line-height:1.5em;color:#fff;border-radius:11px;padding:.5em 1em;display:inline-block;background-color:#0067b859;text-shadow:1px 1px 1px rgba(0,0,0,.3)}

    .nl-box{margin:1.5em 0;padding:1em 0;box-shadow:none;max-width:750px;justify-self:center}

    .nl-box__blue{background-color:#1b71bb;background-image:linear-gradient(#1b71bb 60%,#01a6c1 100%)}

    .nl-box__desc{padding:.5rem 2rem 1rem}

    .nl-box__image{width:100%;height:auto}

    @media screen and (min-width: 48em){.nl-box__desc { padding: 0.5rem calc(2rem + 0.5vw) 1rem calc(2rem + 0.5vw); }}

    .nl-box__desc–heading-link{color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.9)}

    .nl-box__summary{border-bottom:0;color:#fff;font-style:normal;text-shadow:1px 1px 1px rgba(0,0,0,.4)}

    .promo-box–blue{–promo-background:#e7f8ff;–promo-text:#000;–promo-highlight-text:#e7f8ff;–promo-highlight:#006fc6;–promo-highlight–hover:#006fc6}

    .promo-box{background:var(–promo-background);color:var(–promo-text);position:relative;padding:125px 1.5em 2em;margin-top:125px;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center;border-radius:11px;width:100%}

    .promo-box__image-link{position:absolute;display:block;top:0;padding:0;left:50%;transform:translate(-50%,-50%);width:250px;height:250px;text-decoration:none;background:0 0}

    .promo-box__image{width:100%;height:100%}

    .promo-box__cta{background:#fff;color:#d33a2c;text-decoration:none;padding:.5em .8em;border-radius:11px;box-shadow:0 0 1px 1px rgba(0,0,0,.15);background-image:none;font-weight:700;font-size:1.2em;margin:0;position:relative;box-shadow:0 2px 6px rgba(0,0,0,.12);transition:background .4s ease-in-out,color .4s ease-in-out}

    .promo-boxcta:active,.promo-boxcta:focus{outline:0!important;background:#fff;text-shadow:none;box-shadow:inset 0 3px 3px rgba(0,0,0,.3)}

    .promo-box__heading{line-height:1.2;font-size:1.5em;font-weight:700;margin:1.25em 0 0}

    .promo-box__button{background:var(–promo-highlight);border-radius:11px;padding:.8em 1em;font-size:1.15em;text-shadow:1px 1px 1px rgba(0,0,0,.3);text-decoration:none;color:#fff;font-weight:700;display:flex;width:100%;justify-content:center;transition:all .2s ease-in-out}

    .promo-boxbutton:active,.promo-boxbutton:focus,.promo-box__button:hover{border-bottom:none;cursor:pointer;border-color:#dadada}

    .promo-boxbutton:active,.promo-boxbutton:focus{outline:0!important;box-shadow:inset 0 3px 3px rgba(0,0,0,.3)}

    Useful front-end & UX bits, delivered once a week.

    With tools to help you get your work done better. Subscribe and get Vitaly’s Smart Interface Design Checklists PDF via email. 🎁

    On . Trusted by 200,000+ folks.

    (Video) Rust for curious developers — Memory management, zero-cost abstractions, fearless concurrency etc!

    Better Error Handling In NodeJS With Error Classes — Smashing Magazine (8)(ra, yk, il)

    Explore more on

    FAQs

    What is the best method for error-handling? ›

    Error Handling Best Practices
    • Send error logs to an external service. ...
    • Use error objects in rules. ...
    • Use meaningful error code descriptions. ...
    • Exception handling. ...
    • Avoid uninitialized objects in rules. ...
    • Learn more.

    What are 3 error detection techniques? ›

    Error Detection Techniques

    There are three main techniques for detecting errors in frames: Parity Check, Checksum and Cyclic Redundancy Check (CRC).

    What is the three methods that can reduce errors? ›

    Double check your formulas are correct. Make sure measurement takers are well trained. Make the measurement with the instrument that has the highest precision. Take the measurements under controlled conditions.

    How do I improve my node performance? ›

    How to Optimize Node. js APIs
    1. Always Use Asynchronous Functions. ...
    2. Avoid Sessions and Cookies in APIs, and Send Only Data in the API Response. ...
    3. Optimize Database Queries. ...
    4. Optimize APIs with PM2 Clustering. ...
    5. Reduce TTFB (Time to First Byte) ...
    6. Use Error Scripts with Logging. ...
    7. Use HTTP/2 Instead of HTTP. ...
    8. Run Tasks in Parallel.
    22 Aug 2022

    What are the 3 types of errors and how do you handle the exceptions in JavaScript give examples? ›

    There are three types of errors in programming: (a) Syntax Errors, (b) Runtime Errors, and (c) Logical Errors.
    • Syntax Errors. ...
    • Runtime Errors. ...
    • Logical Errors. ...
    • The try... ...
    • The throw Statement. ...
    • The onerror() Method.

    Why does node js prefer error first callback? ›

    Error-first callback in Node. js is a function that returns an error object whenever any successful data is returned by the function. The first argument is reserved for the error object by the function. This error object is returned by the first argument whenever any error occurs during the execution of the function.

    Which one is the strongest error detection method? ›

    Cyclic redundancy check is the most powerful and easy to implement error detection mechanism. Checksum uses addition, whereas CRC is based on binary division. In CRC, the data unit is appended at the end by a sequence of redundant bits, called cyclic redundancy check bits.

    What are the five 5 different types of error detection techniques? ›

    Error Detecting Techniques:

    Single parity check. Two-dimensional parity check. Checksum. Cyclic redundancy check.

    What are two forms of error-handling? ›

    Essentially, there are two types of errors: terminating and non-terminating.

    What is the best way of handling error whenever an unexpected request is triggered? ›

    using error events, and then, triggering following actions to handle the error according to the business logic. By using this approach, the whole process – including the treatment of the errors – is clear for all the personas involved in the project.

    Why we use buffers in Node JS? ›

    Buffers in Node.

    js is used to perform operations on raw binary data. Generally, Buffer refers to the particular memory location in memory. Buffer and array have some similarities, but the difference is array can be any type, and it can be resizable. Buffers only deal with binary data, and it can not be resizable.

    How does node js handle validation errors? ›

    Handling Validation Errors in Node. js
    1. Consider only keys from req. body data.
    2. List the allowed fields.
    3. Perform every() function on each field and by returning boolean(to track) true if entered field is part of the allowed list.
    4. if not part of the allowed list then sends 400 status code with error as invalid updates.
    25 Jun 2020

    What are the 4 sources of error? ›

    Common sources of error include instrumental, environmental, procedural, and human. All of these errors can be either random or systematic depending on how they affect the results.

    What is the most common method of error detection? ›

    One of the most common techniques for detecting transmission errors is a technique known as the cyclic redundancy check (CRC).

    What is the simplest form of error detection? ›

    The use of a parity check is perhaps the simplest form of error detection. With this technique a bit is inserted after a fixed number of bits to maintain either an odd number or an even number of bits.

    What are the 11 effective principles for error reduction designs? ›

    Such errors are part of daily life.
    ...
    • Guard Critical Controls. ...
    • Confirm Critical Actions. ...
    • Make Critical Information Legible and Readable. ...
    • Simplify and Ensure Proper Connections. ...
    • Use Tactile Coding. ...
    • Prevent the Disabling of Life-Critical Alarms. ...
    • Present Information in a Usable Form. ...
    • Indicate and Limit the Number of Modes.

    What are the 3 error types? ›

    When developing programs there are three types of error that can occur: syntax errors. logic errors. runtime errors.

    How can you minimize errors or mistakes? ›

    1. Stop trying to multitask. ...
    2. Eliminate distractions. ...
    3. Use a task tracker or checklists. ...
    4. Try automating your task workflows. ...
    5. Always clarify and ask questions. ...
    6. Carefully review your work. ...
    7. Get a second set of eyes. ...
    8. Take breaks and refresh with a mental pause.

    Which loop is faster in node JS? ›

    You can see that for loops are 3 time faster than array methods like forEach map and reduce . Upon receiving an array element, array methods execute a callback function for each element.

    How can I make NPM faster? ›

    1. 13 npm Tricks for Faster JavaScript Development. ...
    2. Learn the Essential Shortcuts. ...
    3. Set Default npm init Properties. ...
    4. Make Scripts Cross-Platform Compatible. ...
    5. Run Scripts in Parallel. ...
    6. Run Scripts in Different Directories. ...
    7. Delay Running Scripts Until a Port is Ready. ...
    8. List and Select Available Scripts.

    How do I increase response time in node JS? ›

    Another way to improve Node. js server response time is by updating database indexes. This can be done by adding new indexes, removing unused indexes, or rebuilding existing indexes. Adding new indexes can improve query performance by allowing the database to find the data it needs more quickly.

    How many types of errors are there in node JS? ›

    In general, Node. js errors are divided into two distinct categories: operational errors and programmer errors.

    Which is the correct way to handle multiple exceptions with one except? ›

    By handling multiple exceptions, a program can respond to different exceptions without terminating it. In Python, try-except blocks can be used to catch and respond to one or multiple exceptions. In cases where a process raises more than one possible exception, they can all be handled using a single except clause.

    What are the 3 main data types that JavaScript variables can hold? ›

    In Javascript, there are five basic, or primitive, types of data. The five most basic types of data are strings, numbers, booleans, undefined, and null. We refer to these as primitive data types. A single variable can only store a single type of data.

    Which is faster promise or callback? ›

    So from my findings i assure you ES6 promises are faster and recommended than old callbacks. I recommend to get a common understanding of JS event loop.

    Which is better promise or callback? ›

    A callback function is passed as an argument to another function whereas Promise is something that is achieved or completed in the future. In JavaScript, a promise is an object and we use the promise constructor to initialize a promise.

    Which one is better promise and callback? ›

    While callbacks work fine for handling asynchronous code, promises are cleaner and more flexible. Dealing with asynchronous code, meaning code that doesn't execute immediately like web requests or timers, can be tricky.

    What type of error is hardest to fix? ›

    Random Errors:

    Random Errors are errors that can occur in any direction and are not consistent, thus they are hard to identify and thus the error is harder to fix for future experiments.

    Why error correction is better than error detection? ›

    Error detection is a method that can look at some data and detect if it has been corrupted while it was stored or transmitted. Error correction is a step better than error detection; when it detects an error it tries to put the data back to how it should have been.

    Which programming error is the hardest to detect? ›

    Logic Errors

    Logic errors can be the hardest to track down. Everything looks like it is working; you have just programmed the computer to do the wrong thing. Technically the program is correct, but the results won't be what you expected.

    Which algorithm is used for error detection? ›

    The SEC ECC algorithm relies on the redundant parity checking protection of multiple check bits for each data bit. In SEC ECC, the basic unit of error detection—or symbol size—is an individual bit. In the b-adjacent ECC algorithm, the basic unit of error detection is a group of b-adjacent bits.

    What is good error handling? ›

    Capture all errors where appropriate. Ensure error handling functionality in applications, APIs, and libraries provide the appropriate amount of information to callers. Test all possible paths and errors in your systems to ensure proper data processing. Consider standardizing your error messages with an error code.

    What are the strategies or techniques used for error handling? ›

    Common Rules of Error Handling
    • Do not leave unsuccessful results unchecked.
    • Initialize pointers with nulls. ...
    • Minimize the usage of static-length buffers. ...
    • Write readable code.
    • Use standard or already defined error codes if it is possible.
    22 Nov 2002

    What are different types of error handling methods? ›

    Learn about the four main error handling strategies- try/catch, explicit returns, either, and supervising crashes- and how they work in various languages.

    What is better to use to handle unexpected conditions assertions or exceptions? ›

    Use exceptions for conditions you expect to occur, and user assertions for conditions that should never occur.

    How do you handle exceptions gracefully? ›

    And without further ado, here are the list of best practices we promised you.
    1. Clean Up Resources in a Finally Block or Use a Try-With-Resource Statement. ...
    2. Prefer Specific Exceptions. ...
    3. Document the Exceptions You Specify. ...
    4. Throw Exceptions With Descriptive Messages. ...
    5. Catch the Most Specific Exception First. ...
    6. Don't Catch Throwable.
    22 Aug 2019

    What is the difference between error handling and exception handling? ›

    Exception handling differs from error handling in that the former involves conditions an application might catch versus serious problems an application might want to avoid. In contrast, error handling helps maintain the normal flow of software program execution.

    What is difference between buffer and stream in node JS? ›

    So what is the difference between Stream & Buffer? A buffer has a specified, definite length whereas a stream does not. A stream is a sequence of bytes that is read and/or written to, while a buffer is a sequence of bytes that is stored.

    Does buffer increase throughput? ›

    Buffers increase the system throughput while also increasing the production lead time, consequently affecting the product qu...

    What is the main advantages of buffer cache? ›

    Advantages of Buffer

    It simplifies system design. The system places no data alignment restrictions on user processes doing I/O. By copying data from user buffers to system buffers and vice versa, the kernel eliminates the need for special alignment of user buffers, making user programs simpler and more portable.

    How do you handle errors in node JS? ›

    Error handling in Node. js
    1. improve the end-user experience; i.e., providing correct information and not the generic message “Unable to fulfill the request”
    2. develop a robust codebase.
    3. recede development time by finding bugs efficiently.
    4. avoid abruptly stopping a program.
    20 Jan 2022

    Which is better express-validator or Joi? ›

    Express-validator

    So by definition, we can say that: Joi can be used for creating schemas (just like we use mongoose for creating NoSQL schemas) and you can use it with plain Javascript objects. It's like a plug n play library and is easy to use. On the other hand, express-validator uses validator.

    How would you prevent errors in your Nodejs applications? ›

    How Do You Handle Errors in Node. js: Best Practices You Should Follow
    1. Use Custom Errors to Handle Operational Errors. ...
    2. Use a Middleware. ...
    3. Restart Your App Gracefully to Handle Programmer Errors. ...
    4. Catch All Uncaught Exceptions. ...
    5. Catch All Unhandled Promise Rejections. ...
    6. Use a Centralized Location for Logs and Error Alerting.
    2 Feb 2021

    Which error detection method is more efficient? ›

    Which is more efficient? Explanation: Cyclic redundancy check is more efficient than parity check.

    What are the two main methods of error correction? ›

    Error Correction can be handled in two ways: Backward error correction: Once the error is discovered, the receiver requests the sender to retransmit the entire data unit. Forward error correction: In this case, the receiver uses the error-correcting code which automatically corrects the errors.

    Which is the simplest error detection method? ›

    Parity Checking of Error Detection

    It is the simplest technique for detecting and correcting errors. The MSB of an 8-bits word is used as the parity bit and the remaining 7 bits are used as data or message bits.

    Which type of error is usually the most difficult to find? ›

    Logical errors are more difficult to locate because they do not result in any error message. A logical error is a mistake in reasoning by the programmer, but it is not a mistake in the programming language.

    What are the 2 types of errors? ›

    What are Type I and Type II errors? In statistics, a Type I error means rejecting the null hypothesis when it's actually true, while a Type II error means failing to reject the null hypothesis when it's actually false.

    Videos

    1. Виталий Фридман — Big Bang Redesign: Smashing Magazine’s 2017 Relaunch, a Case Study
    (HolyJS)
    2. 🔴 🏖️ Poll and display live data on your site · #GatsbySummerFunctions · Week 4
    (Queen Raae)
    3. Native JavaScript Modules: import {Browsers, Node.js}; export {production};
    (International JavaScript Conference)
    4. TagUI Maintainer Training 1 | Free RPA by AI Singapore
    (Ken Soh)
    5. Records and Sealed Types - Coming Soon to a JVM Near You!
    (InfoQ)
    6. Breaking Changes - James Coglan - JSConf EU 2018
    (JSConf)
    Top Articles
    Latest Posts
    Article information

    Author: Clemencia Bogisich Ret

    Last Updated: 01/13/2023

    Views: 5547

    Rating: 5 / 5 (60 voted)

    Reviews: 91% of readers found this page helpful

    Author information

    Name: Clemencia Bogisich Ret

    Birthday: 2001-07-17

    Address: Suite 794 53887 Geri Spring, West Cristentown, KY 54855

    Phone: +5934435460663

    Job: Central Hospitality Director

    Hobby: Yoga, Electronics, Rafting, Lockpicking, Inline skating, Puzzles, scrapbook

    Introduction: My name is Clemencia Bogisich Ret, I am a super, outstanding, graceful, friendly, vast, comfortable, agreeable person who loves writing and wants to share my knowledge and understanding with you.