NodeJS callback with null as first argument - node.js

I've just started out with NodeJS and trying to get the hang of callbacks.
Today I've seen null passed by as the first argument to the callback in many examples. Please help me understand why it's there and why I need it.
Example 1
UserSchema.methods.comparePassword = function(pwd, callback) {
bcrypt.compare(pwd, this.password, function(err, isMatch) {
if (err) return callback(err);
callback(null, isMatch);
});
};
Example 2
example.method = {
foo: function(callback){
setTimeout(function(){
callback(null, 'foo');
}, 100);
}
}

By convention in node, the first argument to a callback is usually used to indicate an error. If it's something other than null, the operation was unsuccessful for some reason -- probably something that the callee cannot recover from but that the caller can recover from. Any other arguments after the first are used as return values from the operation (success messages, retrieval, etc.)
This is purely by convention and there is nothing to stop you from writing a function that passes success as the first argument to a callback. If you plan to write a library that is adopted by other node users, you will probably want to stick with convention unless you have a very good reason not to.

Related

Why is the response object being returned with multiple parameters when it doesnt appear to take any?

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.

Set variable equal to mongodb key value

var userLat = db.collection('users', function (err, document){
document.findOne({_id: loggedUserID}, function(err, docs) {
console.log(docs.currentUserLat);
})
});
This is my code, I'm trying to get the value that's console logged into the variable. I just can't find the correct syntax to do this. The console log does return the correct value just need to drop it into the variable. Grateful for some help.
What do you want to do with 'docs.currentUserLat'?
You can do what you need to do without saving docs.currentUserLat to a variable that has scope outside of your db.collection call. Some examples:
If you simply want to change the document in your database, take advantage of the many methods specified in the Collections API: http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html. For example, to update the document and simultaneously resave it in the database:
db.collection('users', function (err, document){
document.findOneAndUpdate({_id: loggedUserID},
{currentUserLat: [updated value]},
function(err, docs) {
if(err) console.log(err);
}
)
});
If you just wanted to use docs.currentUserLat inside some node function, you'll need to properly nest the document.findOne function inside a callback (or vice versa). For example, to write currentUserLat to a file using the fs module:
var fs = require('fs');
db.collection('users', function (err, document){
document.findOne({_id: loggedUserID}, function(err, docs) {
fs.writeFile("pathToYourFile", docs.currentUserLat, function(err) {
if(err) {return console.log(err);}
});
});
});
Or, if you want to send it in response to a simple http request:
var http = require('http');
http.createServer(function(request,response){
db.collection('users', function (err, document){
document.findOne({_id: loggedUserID}, function(err, docs) {
response.writeHead(200,{'Content-Type':'text/html'});
response.end(docs.currentUserLat);
});
});
});
The key thing to remember is what JohnnyHK said in their comment: docs.currentUserLat is only available inside the anonymous function passed to findOne. So, whatever it is that you need to do, do it inside this function.
(Reading the link JohnnyHK provided is a great way to get started with understanding asynchronous functions in Node. Another is https://github.com/rvagg/learnyounode)
First of all you have to understand how javascript callback works. After that you will see that nothing assigns docs.currentUserLat to your userLat variable. The reason behind this is that your docs.currentUserLat is available only inside the callback. Think about it in the following way:
You program started to execute and encountered the line: var userLat = .... This line tells: do a callback (which basically asks someone else to do the job), your while your job is being executed the program continues, by assigning userLat to undefined and executes further. Then at some period of time callback finishes and console.log your docs.currentUserLat.
One way to have the desired behavior is to make userLat global and instead of console.log(docs.currentUserLat); do userLat = docs.currentUserLat. The problem that if you will do this, your userLat eventually will have the desired value (if callback will not fail), but you can not predict when. So if you will do
var userLat = db.collection('users', function (err, document){ ... });
.. some other code
console.log(userLat);
you will not be sure that you will get the output. Another way to do put everything in another callback.

NodeUnit testing mysql function test always successful

I'm trying to learn how to use NodeUnit to test my NodeJs code. Ive written the following code, however each time I run the test, the result is OK: 0 assertions, no matter whether the input parameter is valid or not. Can anyone explain why this doesn't work and how I can fix it?
auth.class.js: This function accepts a user ID and returns a username.
exports.username = function(uid, callback) {
db.query('SELECT username FROM ul_logins WHERE id=?', uid, function(err, results){
if (err) throw new Error(err);
if(results.length > 0)
{
callback(null, results[0].username);
}
else
throw new Error("No results.");
});
};
authtest.js: This test will run successful every time, no matter what the uid is, and count 0 assertions.
var auth = require('./auth.class.js');
exports['username'] = function (test) {
auth.username(1, function(err, data){
return test.equal(data, "joe#example.com");
});
test.done();
};
The function you are testing is asynchronous (see the rewritten function below). You need to put the test.done() in the callback function:
exports['username'] = function (test) {
test.expect(2);
auth.username(1, function (err, data) {
test.ifError(err);
test.equal(data, 'joe#example.com');
test.done();
});
};
In your version, test.done gets called before the callback to auth.username is called. Use test.expect to tell nodeunit how many asserts it should receive before test.done is called.
You have a serious problem in your auth.username function. You should not throw in asynchronous code since a try-catch cannot be used to catch the error, leading to uncaught exceptions. You should always pass errors in asynchronous code to a callback as the first argument (convention). Your function should look like:
exports.username = function (uid, callback) {
var query = 'SELECT username FROM ul_logins WHERE id=?';
db.query(query, uid, function (err, results) {
if (err) {
return callback(err);
}
if (results.length === 0) {
return callback(new Error('No user found.'));
}
callback(null, results[0].username);
});
};
Note that errors are handled first (keeps the code neat), and callback calls in the branches are returned to avoid calling the callback multiple times (using else adds a level of indentation).
I get the impression that you are new to Node, and I remember having difficulty over this point too. Consider any function that does something over the network as asynchronous. This could take a long time, so to avoid blocking the process Node gets the OS to handle the task, and takes a callback to call at some point in the future when the OS gives it a result. This is why Node relies so heavily on callbacks. It leaves the Node process free to do other things (like call test.done in your question) while it waits. It also means that try-catch (which can only catch errors thrown in the same 'tick') no longer works. The conventional way to handle errors is to call the callback with the error as the first argument. All other arguments are for actual results.

Node.js error callback

I have a codebase which contains code similar to the code below many times:
function(doc, callback) {
doSomething(function(err) {
if(err) return callback(err);
callback(null, doc);
});
}
I'm wondering if there are any downsides to just combining the explicit error check into:
function(doc, callback) {
doSomething(function(err) {
callback(err, doc);
});
}
I understand that callback handlers are expected to check the err on callback, but in this case it's just bubbling up.
I suppose I'm wondering if based on the way callbacks are generally used, if this is an issue?
There is no difference, the code is doing the same thing. First one is just easier to edit later if you want to add some postprocessing.
Technically, second example provides a "doc" and first don't, but if somebody rely on that, they're doing it very wrong.

Query callback with arguments and synchronous queries

I have two problems implementing a RESTful service using Node.js / node-postgres lib / PostgreDB and both are due to the async nature of JS.
A) I need to pass an extra argument to a callback in client.query(query, callback) call
I am inside a callback of a query and going through an array of recently fetched rows from a DB and want to launch a subsequent query for each of them:
var query = client.query('SELECT * FROM event', queryAllEventsHandler);
function queryAllEventsHandler(err, result){
allEvents = result.rows;
/* allEvents is an JSON array with the following format
[ {"id_event":1, "name":"name of the event"},
{"id_event":1, "name":"name of the event"}
]
*/
for(var i = 0; i<allEvents.length; i++){
client.query('SELECT * FROM days where id_event = $1',[allEvents[i].id_event], function( err, result){
//I want to have a reference to variable i
}
}
In the above example I want to do something like:
client.query('SELECT * FROM days where id_event = $1',[allEvents[i].id_event], function( AN_EXTRA_ARG, err, result)
Where the AN_EXTRA_ARG is an extra argument or a closure in the callback function... How can I achieve this? Should I create an closure with the of i and pass it as a callback's arg? How ? :|
B) "Synchronizing" queries
I need to launch various queries and create a custom JSON from all of them. Since every query and it's callback are asynchronous (waiting for no one) I was looking for a way to "tame" it and among other stuff I found a solution that occured to me in the first place, but seemed a bit "bad/lousy":
Keeping the query count is really the way to go as #jslatts suggests in Synchronous database queries with Node.js?
Hope I
With regards to question A, you could create a function to handle both your queries and only return when the last query is executed and return both results to the callback.
for(var i = 0; i<allEvents.length; i++){
query(client, allEvents[i], function(result1, result2) {
//do something
});
}
function query(client, event, callback) {
client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err1, result1){
client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err2, result2){
callback(result1, result2);
});
});
}
I don't like answering my on question, but this might be of interest to someone.... Regarding the A part of my question. You can assign a custom object to this in your function.
As you know a keyword this corresponds to the Window (top) object when inside a function (unless it's a method function). Using the bind function you can change the reference of this to your own object...
So what I did was, I created a named function queryCallback
function queryCallback(err, result){
//this == Window (default)
}
changed the anonymous callback function to the named one queryCallback:
client.query('SELECT * ... where id_event = $1',[allEvents[i].id_event], queryCallback.bind( {"position":i}, err, result));
Now, note queryCallback.bind( {"position":i}, err, result));
What bind(my_custom_this, [other args]) does is it binds a custom object (in my case {"position":i}) to this inside the function upon which the bind was called...
Now we have this scenario:
function queryCallback(err, result){
//this == {"position":i}
}
Bind explained: http://fitzgeraldnick.com/weblog/26/
A) I personally like lodash (or underscore if you prefer) partial() for this. It takes a function and a number of arguments and returns a function with the provided arguments applied and the remaining arguments still open. It's very much like the functional concept of currying.
B) For combining multiple asynchronous results I highly recommend async. The syntax will take a little getting used to, but makes thing like this very easy. Quick sample:
async.parallel([
one: function(callback){
db.fetch(options, callback);
},
two: function(callback){
db.fetch(options, callback);
}
],
function(err, results){
// this callback will get called when either parallel call gives an error
// or when both have called the callback
if (err) {
// handle error
return;
}
// get the results from results.one and results.two
});
== Added in edit ==
Actually lodash also provides a nicer (imho) albeit slightly more expensive (due to function calls) solution for your problem A):
_(allEvents).each(function(event, index, array) {
client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err, result) {
// Just use 'index' here, which doesn't change during the each
}
});
For B), your options include async or via a Promise library (such as Q, when.js, Bluebird, etc...)

Resources