Node.js Throwing error known as bad practice but essential for TDD

I've heard many people say that throwing errors in Node is bad practice and you have to manually handle them through the CommonJS callback syntax:

somethingThatPassesAnError( function(err, value) {
    if (err) console.log("ERROR: " + err);
});

      

However, I've found in several unit test environments (Mocha, Should.js, Gently) that it seems like they want you to get it throw

wrong when something happens. I mean, of course, you can design your tests to check for equality of variables and check for non-null in vars errors, but in the words of Ryan Dahl himself, β€œyou have to write your structure to make the right things easy to use and wrong things are hard to do. "

So what gives? Can anyone explain why this practice exists? Should I throw fatal exceptions like require()

if the module cannot be found?

+3


source to share


4 answers


This is because nodejs programs tend to use heavy async and as a result, errors often occur after your try / catch has already completed successfully. Consider this contrived example.

function foo(callback) {
  process.nextTick(function() {
    if (something) throw "error";
    callback("data");
  });
}

try {
  foo(function(data) {
    dosomething(data);
  });
} catch (e) {
  // "error" will not be caught here, as this code will have been executed
  // before the callback returns.
}

      



The typical node pattern, the first argument in the callback is an error, fixes this problem by providing a consistent way to return errors from asynchronous code.

function foo(callback) {
  process.nextTick(function() {
    if (something) return callback("error");
    callback("data");
  });
}

foo(function(error, data) {
  if (error) return handleError(error);
  dosomething(data);
});

      

+3


source


I understand that the case versus throwing exceptions in JavaScript comes with heavy use of asynchronous templates. When an error occurs on a different stack, you cannot catch it. In these cases, use the parameter err

as the first parameter for the callback.



I don't think this is the same as saying "never quit." If I have synchronous code and an exception is thrown, I throw it. There are different opinions, but if callbacks are not involved at all, I see no reason not to use throw

.

+2


source


I tend to follow the Joyent Error Handling guidance in Node.js for this. The downside is that there are actually two types of errors (operators and programmers) and three ways to pass errors (emitting an error event on the event emitter, returning a callback with an error argument as nonzero, and throwing an error).

Operational errors are errors that you expect can occur and can be handled, i.e. not necessarily errors. Programmer errors are errors in the code itself. If you are writing code and expecting an error, then any of the templates for conveying the error are valuable. For example:

  • If an error occurs inside an asynchronous function that accepts a callback, using a callback callback (new error ("Yadda yadda yadda")) is the correct solution (if you cannot handle the error in the function).
  • If the error occurs inside a synchronous function and is an interrupt problem (i.e. the program cannot continue without the operation that was attempted) then exploding with an unchecked thrown error is acceptable.
  • If the error occurs in a synchronous function, but it can be handled, then the error needs to be handled, otherwise it must be thrown, and perhaps the parent function can handle it, perhaps not.

, , try/catch ( JSON.parse : function jsonParseAsync (json, cb) {var out, err; try {out = JSON.parse(json)} catch (e) {err = e}; return cb (err, out);}). promises, ( , promises ). , , ( , , ). .

+1


source


I would suggest using exceptions to handle critical errors, similar to how the require () function works. If this function raises a Node.js error, then the error that I'm sure will be fixed in time.

0


source







All Articles