It is a convention in node to pass an error parameter to asynchronous operations:
async.someMagicalDust(function(callback) {
// some asynchronous task
// […]
callback();
}, function(err) {
// final callback
if(err) throw err;
// […]
});
Maybe I'm too naive, but I've never been a big fan of the if(variable) notation — probably inherited from C, for reasons that have already been discussed many times in the past.
On the other hand, I have sometimes encountered a null parameter and this error check:
if(typeof err !== 'undefined' && err !== null)
is a bit too verbose.
Another solution would be
if(err != null)
but I think the non-strict check can be tricky, even though I consider it normal when comparing with null.
What's the best way to check error parameters in node?
Use if(err).
It is designed to be used in this fashion. Node-style callbacks are supposed to set the error to a non-falsy value only in case of actual error. You won't find any sane example of setting err to '' or 0 to signify error.
Just like YlinaGreed has noted, if module conventions cnahge from null to undefined to 0 to maybe even NaN, you are still safe. I've never been hit by this having only used if(err).
On the other hand, you may want to use coffescript, which would translate for you
unless err? then...
into
if (typeof err === "undefined" || err === null) {
mimicking the most common pattern.
Some links to corroborate the if(err) approach:
https://gist.github.com/klovadis/2548942
http://caolanmcmahon.com/posts/nodejs_style_and_structure/ (by Caolan McMahon, author of async)
http://thenodeway.io/posts/understanding-error-first-callbacks/
The convention seems to be passing an error object as the first argument and null for no error so even if you pass an empty object, it's still an error.
If you use the popular express framework, you should have used the next callback to return from middleware, which follows the errback convention.
I believe that most people prefer more concise next() than next(null), which means that the first argument will evaluate to undefined rather than null, and this is certainly perfectly normal usage.
To me, the best way to handle error is the "if (err == null)"
This is the only case I am using the non strict operator, for these reasons:
The only over solution which always works is very verbose, as you said before
You could also check only on "null" or "undefined", but I did this once, and a few month later, I just updated my dependencies and... The convention changed, and the module was sending null instead of undefined.
This is mostly a matters of "convention", I have mine, and you certairnly have your's too... Just be careful to chose one of the two "good" ways.
Node's primary callback convention is to pass a function with err as the first parameter. In my experience its always been safe to check if error is truthy - in practice if your error comes out null when there IS an error then the problem lies more with the implementation. I would always expect if err is null that no error occured. It may be confusing due to the use of separate functions for errors and successes, something that is more in the style of JQuery.Ajax and promises. I tend to find double callbacks to be a bit too wordy to call.
Given your example it seems you're using the async library which is excellent. If I am looking to perform a parallel option this is how I set it up:
function doAThing(callback) {
var err;
// do stuff here, maybe fill the err var
callback(err);
}
function doAsyncThings(callback) {
var tasks = [function(done) { // stuff to do in async
doAThing(function(err) {
done(err);
});
}];
async.parallel(tasks, function(err) { // single callback function
callback(err); // I send the error back up
});
}
Note that instead of throwing the error I bubbled it back up the request chain. There are few instances which I'd want to actually throw an error since you're basically saying "crash the whole app".
I find it to be simpler and reduces the amount of parameters you have to use to call your functions. When you use this convention throughout you you can simplify by simply passing the callback as a parameter instead of creating a new anonymous function, like so:
function doAThing(callback) {
var err;
// do stuff here, maybe fill the err var
callback(err);
}
function doAsyncThings(callback) {
var tasks = [function(done) { // stuff to do in async
doAThing(done);
}];
async.parallel(tasks, callback); // the error is sent back to the original function
}
I find that generally you want to handle those errors in the functions they are called in. So in this case the caller of doAsyncThings can check if there is an error and handle it appropriate to its own scope (and perhaps provide better information to the user if it is say an API).
Related
I am new learning to create rest API's using Node, Express and MySQL. I have my function removeAll that takes no parameters, it passes the result object into an arrow function which then runs a sql function which then takes another function as a parameter (err, res). Inside of the nested arrow function if we do not have any errors and the affected rows does not equal 0 we get to the result which returns (null, res). Now my confusion is as to why result contains (null, res) rather than just res. I am also confused as to how res is actually being assigned, I see that it is being passed into the arrow function but we dont explicitly set what res is.
sql.query("DELETE FROM customers", (err, res) => {
if (err) {
console.log("error: ", err);
result(null, err);
return;
}
if (res.affectedRows == 0) {
// customer not found with the id
result({ kind: "not_found" }, null);
return;
}
console.log("deleted customer with id: ", id) {
result(null, res);
}
});
};
result is a node-style callback, where the first parameter is the error (if any; if no error, first parameter is null), and the second parameter is the result (if no error is encountered).
The general approach is very similar to the sql.query callback you're using:
sql.query("DELETE FROM customers", (err, res) => {
Just like how its callback defines the error parameter first, and the result second, you similarly want to call result with the error as the first parameter, or else with the result as the second parameter.
That said, result is a pretty confusing variable name - it's a callback, not a result which contains data, so you might want to rename it to something more appropriate, so as to reduce potential confusion.
I am also confused as to how res is actually being assigned
It's handled by the internals of sql.query. When the query resolves successfully, it will do something like callback(null, results). When the query fails, it will do something like callback(someError). callback is the callback that you pass to sql.query.
Now my confusion is as to why result contains (null, res) rather than just res.
That's the standard way old-style Node.js callbacks work: The first argument is an error or null, and if the first argument isn't an error, the second argument contains the data "returned" by the call.
These days, you'd use a promise, but that's how the old-style callbacks work.
I am also confused as to how res is actually being assigned, I see that it is being passed into the arrow function but we dont explicitly set what res is.
The sql.query function is what calls the callback you pass into it. That's where res comes from, it's the result of the database operation. sql.query also follows the standard old-style Node.js callback pattern.
A methodological question:
I'm implementing an API interface to some services, using node.js, mongodb and express.js.
On many (almost all) sites I see code like this:
method(function(err, data) {
assert.equal(null, err);
});
The question is: should I keep assert statements in my code at production time (at least for 'low significance' errors)? Or, are these just for testing code, and I should better handle all errors each time?
You definitively should not keep them in the production environment.
If you google a bit, there are a plethora of alternative approaches to strip out them.
Personally, I'd use the null object pattern by implementing two wrappers in a separate file: the former maps its method directly to the one exported by the module assert, the latter offers empty functions and nothing more.
Thus, at runtime, you can plug in the right one by relying on some global variable previously correctly set, like process.env.mode. Within your files, you'll have only to import the above mentioned module and use it instead of using directly assert.
This way, all around your code you'll never see error-prone stuff like myAssert && myAssert(cond), instead you'll have ever a cleaner and safer myAssert(cond) statement.
It follows a brief example:
// myassert.js
var assert = require('assert');
if('production' === process.env.mode) {
var nil = function() { };
module.exports = {
equal = nil;
notEqual = nil;
// all the other functions
};
} else {
// a wrapper like that one helps in not polluting the exported object
module.exports = {
equal = function(actual, expected, message) {
assert.equal(actual, expected, message);
},
notEqual = function(actual, expected, message) {
assert.notEqual(actual, expected, message);
},
// all the other functions
}
}
// another_file.js
var assert = require('path_to_myassert/myassert');
// ... your code
assert(true, false);
// ... go on
Yes! asserts are good in production code.
Asserts allow a developer to document assumptions that the code makes, making code easier to read and maintain.
It is better for an assert to fail in production than allow the undefined behaviour that the assert was protecting. When an assert fails you can more easily see the problem and fix it.
Knowing your code is working within assumptions is far more valuable than a small performance gain.
I know opinions differ here. I have offered a 'Yes' answer because I am interested to see how people vote.
probably no
ref: When should assertions stay in production code?
Mostly in my code i put error handling function in a separate file , and use same error method everywhere, it mostly depends on logic anyways
like ppl generally forget this
process.on('uncaughtException', function (err) {
console.log(err);
})
and err==null doesn't hurts , it checks both null and undefined
I'm new to node.js and using it for a backend that takes data from syslog messages and stores it to a database.
I've run into the following type of serial operations:
1. Query the database
2. If the query value is X do A. otherwise do B.
A. 1. Store "this" in DB
2. Query the database again
3. If the query value is Y do P. otherwise do Q.
P. Store "something"
Q. Store "something else"
B. 1. Store "that" in the DB
2. Store "the other thing" in the DB
The gist here is that I have some operations that need to happen in order, but there is branching logic in the order.
I end up in callback hell (I didn't know what that is when I came to Node.. I do now).
I have used the async library for things that are more straight forward - like doing things in order with async.forEachOfSeries or async.queue. But I don't think there's a way to use that if things have to happen in order but there is branching.
Is there a way to handle this that doesn't lead to callback hell?
Any sort of complicated logic like this is really, really going to benefit from using promises for every async operation, especially when you get to handling errors, but also just for structuring the logic flow.
Since you haven't provided any actual code, I will make up an example. Suppose you have two core async operations that both return a promise: query(...) and store(...).
Then, you could implement your above logic like this:
query(...).then(function(value) {
if (value === X) {
return store(value).then(function() {
return query(...).then(function(newValue) {
if (newValue === Y) {
return store("something");
} else {
return store("something else");
}
})
});
} else {
return store("that").then(function() {
return store("the other thing");
});
}
}).then(function() {
// everything succeeded here
}, function(err) {
// error occurred in anyone of the async operations
});
I won't pretend this is simple. Implemented logic flow among seven different async operation is just going to be a bit of code no matter how you do it. But, promises can make it less painful than otherwise and massively easier to make robust error handling work and to interface this with other async operations.
The main keys of promises used here are:
Make all your async operations returning promises that resolve with the value or reject with the failure as the reason.
Then, you can attach a .then() handler to any promise to see when the async operation is finished successfully or with error.
The first callback to .then() is the success handler, the second callback is the error handler.
If you return a promise from within a .then() handler, then that promise gets "chained" to the previous one so all success and error state becomes linked and gets returned back to the original promise state. That's why you see the above code always returning the nested promises. This automates the returning of errors all the way back to the caller and allows you to return a value all the way back to the caller, even from deeply nested promises.
If any promise in the above code rejects, then it will stop that chain of promises up until an actual reject handler is found and propagate that error back to that reject handler. Since the only reject handler in the above code is at the to level, then all errors can be caught and seen there, no matter how deep into the nested async mess it occurred (try doing that reliably with plain callbacks - it's quite difficult).
Native Promises
Node.js has promises built in now so you can use native promises for this. But, the promise specification that node.js implements is not particularly feature rich so many folks use a promise library (I use Bluebird for all my node.js development) to get additional features. One of the more prominent features is the ability to "promisify" an existing non-promise API. This allows you to take a function that works only with a callback and create a new function that works via a promise. I find this particularly useful since many APIs that have been around awhile do not natively return promises.
Promisifying a Non-Promise Interface
Suppose you had an async operation that used a traditional callback and you wanted to "promisify it". Here's an example of how you could do that manually. Suppose you had db.query(whatToSearchFor, callback). You can manually promisify it like this:
function queryAsync(whatToSearchFor) {
return new Promise(function(resolve, reject) {
db.query(whatToSearchFor, function(err, data) {
if (!err) {
reject(err);
} else {
resolve(data);
}
});
});
}
Then, you can just call queryAsync(whatToSearchFor) and use the returned promise.
queryAsync("foo").then(function(data) {
// data here
}, function(err) {
// error here
});
Or, if you use something like the Bluebird promise library, it has a single function for promisifying any async function that communicates its result via a node.js-style callback passed as the last argument:
var queryAsync = Promise.promisify(db.query, db);
I have an aysnc function that takes an options object and callback
function myFunc(options,callback) {
// do stuff
callback(null);
}
being the defensive-minded guy that I am, I want to check for any potential problems in the parameters
so the first thing I did was to add a test for the options.name (because I need that property)
function myFunc(options,callback) {
if (!options.name) { callback(new Error("name must be specified")) }
// do stuff
callback(null);
}
but - this led to a train of thoughts .. what if
options are an empty or null object
options where not specified, just a callback passed
what if no parameters were passed at all ?
I want to check that my thoughts are right here -
options is null / empty. callback is defined -> callback with error
options is undefined. There are no options and no callbacks -> throw a new error
options is defined, callback is not
typeof options is a function -> use options as the callback, with an error
typeof options is not a function -> throw an error
so, that's a lot of checks ... do people really do all of this ? What is the best practice to ensure parameters are present and correct ?
Since this question has a sense of personal touch, here's mine:
The purpose of a callback is to provide results of an asynchronous operation. As such, it only needs to be called asynchronously. If anything is prohibiting your code from completing its task, and you can identify that synchronously, either return an error value if one is defined or throw.
If the asynchronous operation failed, use the callback to notify.
Side note options can be undefined AND callback can be a valid function at the same time. Don't assume otherwise.
var func = function(p){
if (p == null){
alert('passed null');
}
if (typeof p === 'undefined'){
alert('not passed at all')
}
you can check it here: https://jsfiddle.net/1s1nqdc7/
try
p = req.params.name
Item.update('name': p, req.body , {upsert: true}, (err) ->
if err?
throw err
res.send("ok")
)
catch e
handle_error(e, "Error salvando hoja de vida.", res)
This produces an error in my code right now - that's alright, but why does my nodejs program crash even if I have a try catch here?
The error is:
MongoError: Mod on _id not allowed
(so it must be in the update call)
I am specifically looking for a way to catch an error, I already know how to get rid of it.
Ah yes, you have entered the realm of asynchronous code. The reason you pass a callback into your MongoDB calls like Item.update(..., callback) is because the MongoDB driver is written to be asynchronous. Consider this (mongoose code):
var user = User.findOne({ name: 'joe' });
doSomethingElse();
If it had structured its API like the above code then your entire application would halt until User.findOne() returned the results from the database. Your doSomethingElse() call wouldn't be invoked until the user was retrieved, even if you don't do anything with user inside doSomethingElse. This is a big no no these days and especially in node which has been written to be asynchronous as much as possible. Have a look at the following:
User.findOne({ name: 'joe' }, function (err, user) {
if (err) return console.error(err);
console.log('Do stuff with user... ;)');
});
doSomethingElse();
The above code is asynchronous. The findOne function returns immediately and doSomethingElse is able to begin even before the user is ever retrieved from the database. But of course we still want to do stuff with our user, so in order to accomplish this we pass an anonymous function in to be used as a callback. The MongoDB driver is smart enough to call that function when it's all done retrieving data.
Wrapping the above code in a try/catch would be pointless, unless you suspected the findOne function to throw an exception (Which you shouldn't. It returns immediately remember?).
try {
User.findOne({ name: 'joe' }, function (err, user) {
throw new Error("Something went wrong...");
});
} catch (err) {
console.error(err);
}
The above error would still crash your program because it happened long after findOne returned and your program moved on way beyond that precious try/catch. This is the very reason why your callback function receives an err argument. The MongoDB driver knows that if some error occurs while fetching your data it would be no good to throw an exception and call it good. This is because all this processing has happened later on subsequent trips through the event loop, having left your try/catch behind several iterations ago.
To get around this the MongoDB driver wraps its own internal synchronous code in a try/catch where it actually will handle the exception and then it invokes your callback passing in the error as the first argument. This allows you to check that argument and handle any errors within your callback.
I wrote an entire blog post explaining callbacks, as well as another way of handling asynchronous code called "promises" and I think it would help clarify some things for you :) http://codetunnel.io/what-are-callbacks-and-promises
I hope that helps answer your question.
Maybe I'm wrong (because I don't know Coffeescript), but I suppose the problem is, that your try/catch is outside the callback function. The catch doesn't affect your err -> so the exception is not caught by you, but by node.js.
If I'm wrong, could you perhaps provide the compiled JavaScript code?
Edit
Usually one would handle the error more like this (without try/catch):
Item.update('name': p, req.body , {upsert: true}, (err) ->
if err?
log.error('error updating Item name=' + name)
res.status(500).end()
return
res.send("ok")
)
Probably your handle_error will do this already.
When programming in node.js, I use try/catch only for JSON.parse or if I have a lot of unchecked input which might have wrong types or might be null and I'm too lazy to check all input manually. Surrounding asynchronous functions with try/catch is only helpful if the function has programming errors (e.g. not checking your input correctly).