Use Custom Error in Nodejs with async - javascript

I am using async in a Nodejs application to run a series of functions in series. Each function calls the callback with an err (Can be null) and a result.
What I want to do is check in the series callback for a particular error ... a custom error:
async.series({
one: function(callback){
// Doing Stuff
if(No good)
callback(new error('Custom Error'), 'Failure');
else
callback(null, 1);
},
two: function(callback){
// Doing Stuff
if(No good)
callback(new error('Custom Error 2'), 'Failure');
else
callback(null, 2);
}
},
function(err, results) {
if(err) {
// Test for which error was thrown above
}
});
Any ideas on creating custom error and then testing for them in this context would be great.

You could make a custom error class:
var util = require('util');
var MyError = function (msg) {
MyError.super_.apply(this, arguments);
};
util.inherits(MyError, Error);
// use it in your callback
callback(new MyError(), ...);
// check for it
if (err instanceof MyError) {
...
};

Related

Javascript testing - function called with specfic argument

I am trying to write a unit test for a function but cannot figure out how to check if it makes a call to a nested function with a specific argument. I am assuming I will need to use sinon alongside chai and mocha for this, but I could really use some help.
The function I would like to test looks like:
function myFunc(next, value) {
if (value === 1) {
const err = new Error('This sets an error');
next(err);
} else {
next();
}
}
I would like to test if next is called with or without the err variable. From what I read so far I should use a spy for this (I think) but how would I use that spy? Looking at this example from the Sinon docs it is unclear to me where PubSub comes from:
"test should call subscribers with message as first argument" : function () {
var message = "an example message";
var spy = sinon.spy();
PubSub.subscribe(message, spy);
PubSub.publishSync(message, "some payload");
sinon.assert.calledOnce(spy);
sinon.assert.calledWith(spy, message);
}
Source: https://sinonjs.org/releases/latest/assertions/
If you have a function like this
function myFunc(next, value) {
if (value === 1) {
const err = new Error('This sets an error');
next(err);
} else {
next();
}
}
The test could look like this
it ('should call the callback with an Error argument', function (done) {
const callback = (err) => {
if (err && err instanceof Error && err.message === 'This sets an error'){
// test passed, called with an Error arg
done();
} else {
// force fail the test, the `err` is not what we expect it to be
done(new Error('Assertion failed'));
}
}
// with second arg equal to `1`, it should call `callback` with an Error
myFunc(callback, 1);
});
so you don't necessarily need sinon for that

NodeJS Mongodb distinct to array does not work

Hello try to use an mongodb distinct query with NodeJS (Async). In the GUI of Mongo this query works but in Node it returns the following error
TypeError: db.collection(...).distinct(...).toArray is not a function
The error returns on the following statement:
mongo.connect(uri, function (err, db) {
console.info('MONGODB START CHECK COLLECTIONS')
var tasks = [ // Load businessrules
function (callback) {
db.collection('businessrules').find({typeBusinessRule: 'SpiderGraphExeption'}).toArray(function (err, businessrules) {
if (err) return callback(err);
locals.businessrules = businessrules;
callback();
});
},
// Load stgOmniTracker
function (callback) {
db.collection('stgOmniTracker').find({}).toArray(function (err, tickets) {
if (err) return callback(err);
locals.tickets = tickets;
callback();
});
},
// HERE STARTS THE ERROR
function (callback) {
db.collection('stgOmniTracker').distinct("Responsible Group").toArray(function (err, group) {
if (err) return callback(err);
locals.group = group;
callback();
});
}
];
console.info('--------------- START ASYNC ------------------------')
async.parallel(tasks, function (err) {
if (err) return next(err);
var businessrules = locals.businessrules, tickets = locals.tickets, resultSet = {}, aggCountsPerDayCattegory = [], group = locals.group
db.close()
}
I hope you can help me to fix this. Manny Thanks
Erik
In the mongodb docs you can see that distinct returns null.
distinct(key[, query][, options], callback)
Arguments:
key (string) – key to run distinct against.
[query] (object) – option query to narrow the returned objects.
[options] (object) – additional options during update.
callback (function) – this will be called after executing this method.
The first parameter will contain the Error object if an error occured, or null otherwise.
While the second parameter will contain the results from distinct or null if an error occured.
**Returns: **
null
It takes a callback as the last argument. In this callback, the second argument contains the results you are looking for.
So your updated code would look like this:
function (callback) {
db.collection('stgOmniTracker')
.distinct("Responsible Group", function (err, group) {
if (err) return callback(err);
locals.group = group;
callback();
});
}
db.collection('stgOmniTracker').distinct("Responsible Group", function(err, result)
{
//your code here
});

Executing multiple HTTP requests sequentially using async.js

How can I execute multiple HTTP requests sequentially using async.js . I checked the async.js documentation but couldn't figure out, how to do that. I want to achieve the same thing as below code using async.js callback style.
var http = require('http');
var Q = require('q');
var URL="http://localhost:3000";
var getPromise=function(url) {
var deferred = Q.defer();
var req = http.get(url, function(response) {
if(response.statusCode < 200 || response.statusCode > 299){
deferred.reject(new Error('ErrorCode '+response.statusCode))
}
var result="";
response.on('data',function(chunk){result +=chunk;} )
response.on('end',function(){deferred.resolve(result);} )
});
req.on('error',function(err){
console.error('Error with the request:', err.message);
deferred.reject(err);
});
req.end();
return deferred.promise;
}
getPromise('http://localhost:3000/olympic/2016/ranking/4')
.then(function(data){
console.log("Response 1 "+data)
return getPromise(URL+'/iso/country/'+JSON.parse(data).Country);
})
.then(function(data){
console.log("Response 2 "+data)
return getPromise(URL+'/olympic/2016/medal/'+JSON.parse(data).iso);
})
.then(function(data){
console.log("Response 3 "+data)
})
.catch(function(err){
console.log(err)
});
I got it, I needed async.waterfall it takes an array of functions and execute them one by one. Also we can pass result from previous function execution to the next one
var async = require('async');
async.waterfall([
function task1(done) {
console.log('start!');
setTimeout(function(){
console.log("T1 Complete");
// <- set value to passed to step 2
done(null, 'Value from step 1');
},5000);
},
function task2(task1Result, done) {
console.log(task1Result);
setTimeout(function(){
console.log("T2 Complete");
// <- set value to passed to step 3
done(null, 'Value from step 2');
},1000);
},
function task3 (task2Result, done) {
console.log(task2Result);
setTimeout(function(){
console.log("T3 Complete");
// <- no value set for the next step.
done(null);
},100);
}
],
function (err) {
if (err) {
throw new Error(err);
} else {
console.log('No error happened in any steps, operation done!');
}
});
Looking over the code a bit and trying to understand it more, I believe that async.waterfall is the function you'll need. What this will do is run each function in order, passing its results to the next function in the sequence. Here's an example:
async.waterfall([
function(callback)
{
// Function 1: do request here...
callback(null, val); // replace null with a value if you want the waterfall to error and go straight to the end
},
function(val, callback) {
// Function 2: do your second request here
callback(null, val1, val2, val3); // you can pass any number of variables you like, just make sure the next function in the sequence expects them
},
function(val1, val2, val3, callback)
{
// Function 3: do your third request here
callback(null, result);
} // this can go on for as long as you like
], function(err, result)
{
// this will be called immediately if the first parameter in any of the callbacks is not null, or when all the functions have run
});

What's the best way to get a function return to wait until an asynchronous operation has finished?

Given the following prototype function:
Client.prototype.getLocalIp = function() {
var rtc = new window.RTCPeerConnection({iceServers: []});
rtc.createDataChannel('', {reliable: false});
var that = this;
rtc.onicecandidate = function(event) {
if (event.candidate) {
that.localIp = grep(event.candidate.candidate);
}
};
rtc.createOffer(function (offer) {
that.localIp = grep(offer.sdp);
rtc.setLocalDescription(offer);
}, function (error) {
console.warn('Fetching local IP failed', error);
});
var grep = function(sdpOrCandidate) {
// Does lots of string processing stuff and returns a string
}
console.log("Returning from function");
console.log(this.localIp);
}
How can I stop the function from returning until the grep function has finished doing its business and returned a value? Here's a JSFiddle demonstrating what I mean: http://jsfiddle.net/tjkxcL1j/
If you look in your browser console you should see that the getLocalIp() function is returning null first until the async stuff from rtc.onicecandidate and/or rtc.createOffer is finished.
Your function needs to accept a callback argument
Client.prototype.getLocalIp = function getLocalIp(done) {
// ...
rtc.createOffer(function (offer) {
that.localIp = grep(offer.sdp);
rtc.setLocalDescription(offer);
// call the callback here
done(null, that.localIp);
},
function (error) {
console.warn('Fetching local IP failed', error);
// call the callback with an error here
done(error);
});
};
Then you can use it like this
client.getLocalIp(function(err, ip){
if (err) return console.error(err.message);
console.log("client ip", ip);
});
However, as #zerkms mentions in a comment, this is only going to work if actually async operations are happening. Examples include accessing information over a network or accessing the disk.

My callbacks are wrong - I am returning my response to my error object - Nodejs

I am trying to learn node and understand how callbacks are working. I am doing this by trying to use the async lib. I am trying to hit my db with 2 separate calls and use the async lib to let me know when my object is ready to build. Here is my aysnc code:
async.parallel({
one: function(callback) {
getUser(id, callback);
},
two: function(callback) {
getUserServices(id, callback);
}
}, function(err, results) {
if(err) {
console.log(err);
new Error();
}
res.json(result);
});
Here are what my functions look like where I am calling the db. There are both basically the same function:
var getUser = function(id, callback) {
var query = client.query('SELECT * FROM USERS WHERE USER_ID=$1', [id]);
query.on('row', function(row, result) {
result.addRow(row);
});
query.on('end', function(result) {
callback(result);
});
};
My code hits the db and returns the user, but when it goes back up to the async code the user is in the err object. What am I doing wrong? How do I properly set up callbacks?
As pointed by damphat, your code should be
//additionally, handle errors
query.on('error', function(err){
callback(err) // The first argument to callback should be an error object
})
query.on('end', function(result){
callback(null, result) //passing null error object
})

Categories

Resources