Nodejs async.series not executing all the methods - node.js

I am trying to use 'async' for my work, so I have written a sample program to make sure that works. async.parallel() works as expected, but not the async.series(). Not sure what I am missing. Can anyone take a look at this sample code and point out the problem/mistake?
async.series([task1, task2]) is just executing 'task1' ONLY.
const async = require('async');
var firstThing = function() {
setTimeout(function(){console.log('IN the First thing')}, 1000);
};
var secondThing = function () {
setTimeout(function(){console.log('IN the second thing')}, 1500);
};
async.series(
[
firstThing,
secondThing
],
function (err, result) {
console.log('blah blah '+result);
});
when I run this code, I get
IN the First thing
and exits. Why is the second task not being called? what am I missing?
Thanks.

You have to call back when you finish each of the functions you want to run in series:
const async = require('async');
var firstThing = function(callback) {
setTimeout(function(){console.log('IN the First thing')}, 1000);
callback(/* pass error or callback*/);
};
var secondThing = function (callback) {
setTimeout(function(){console.log('IN the second thing')}, 1500);
callback(/* pass error or callback*/);
};

Related

Node.js sinon stubbing a function in parallel executions causes failed tests

I have 2 test cases which test the same function just taking 2 different executions paths, so to illustrate:
MyClass.prototype.functionBeingTested = function() {
if (this.check1()) {
this.isCheck1Called = true;
} else if (this.check2()) {
this.isCheck1Called = false;
} else {
...
}
};
My 2 test cases are as follow:
it('should take check1() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check1Stub sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});
it('should take check2() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check2Stub sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});
Now by default, check1() returns false so I don't stub it in the second test case, but by the time the second case is running, the check1() function stub is still active and causes the second case to enter the execution path of the first case as-well, making the second case test fail.
I understand it's a problem of test running in parallel and the first sinon stub still being used by the first test case, is there anyway I can solve this problem?
At the end of the first test, you should restore the original method (which is always a good thing, to prevent tests from being influenced by previous tests):
check1Stub.restore()
Or, alternatively, you can use a Sinon sandbox to run each test in:
describe('MyClass', function() {
beforeEach(function() {
this.sinon = sinon.sandbox.create();
});
afterEach(function() {
this.sinon.restore();
});
it('should take check1() execution path', function() {
var myClass = new MyClass({}, {}, {});
// `this.sinon` is the sandbox
var check1Stub = this.sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});
it('should take check2() execution path', function() {
var myClass = new MyClass({}, {}, {});
var check2Stub = this.sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});
});
(See mocha-sinon, which does exactly the same)

'then' function is not never getting called by Mocha for assertion checking

I have written the following test case in Mocha, where the my code uses Q module.
var expect = require("chai").expect;
var utils = require("../Utils.js");
var utils1 = require("../a.js");
var sinon = require('sinon');
var request = require('requestretry');
var querySys = require('../b.js');
var Q = require("q");
describe("Sample", function () {
var results;
describe("#get()", function () {
before(function (done) {
done();
});
it("equal", function () {
var deferred = Q.defer();
var responseData = {};
responseData.code = 200;
responseData.data = [{a:1,b:2}];
deferred.resolve(responseData);
//querySys1 method uses Q promises. That is how I stubbed the response.
sinon.stub(querySys, 'querySys1').returns(deferred.promise);
//get function internally calls querySys1. Hence I have stubbed that.
results = utils1.get(specification);
results.then(function (data) {
//Here I do see data coming as {in:1, out:1}. But still the test case is passing when compare it with {}.
console.log(data);
//Ideally, it should have failed. But it is passing.
expect(data).to.be.equal({});
});
});
after(function (done) {
done();
})
});
});
So, if you see, I am trying to do assertion check in results.then part. I have printed the response, which I am receiving. That is coming as expected. But I am intentionally trying to match with wrong value, but test case is still passing.
Since your test does not include a callback, execution runs through the main block and declares the test as passing without waiting for the result of the then function. You need to let mocha know to wait for the callback:
it("equal", function (done) {
...
results.then(function (data) {
console.log(data);
expect(data).to.be.equal({});
return done();
});
});
When I changed results.then to results.done, test started failing as expected. Can someone say whether this is the right approach.

Processing a method synchronously in Node.js

I've inherited some Node.js code and I need to add some functionality. However, I'm not sure syntactically how to accomplish my goal due to the asynchronous nature of Node. Currently, I have a function defined like this:
return {
myEntryPoint: function(req, res) {
var results = getResults();
res.send(200, results);
}
};
Several pieces are calling this function already. Inside of it, I'm calling a function called getResults which is defined like this:
var getResults = function() {
var results = [];
async.series([
function(callback) {
// add to results
},
function(callback) {
// add to results
}
]);
return results;
};
My problem is, I need to wait until all of the functions inside of the async.series call are made before I return the results. How do I do this?
You could change it to add a callback. Series has an optional callback to run once all the functions have completed within.
var getResults = function(finished) {
var results = [];
async.series([
function(callback) {
// add to results
},
function(callback) {
// add to results
}
], function() {
//Called when series is finished
finished(results);
});
};
And to get the results,
return {
myEntryPoint: function(req, res) {
getResults(function(results) {
res.send(200, results);
});
}
};
The usual way to handle this is to take a callback that uses the argument in question.
results = getResults(args);
someFunction(results);
Is equivalent to
function getResults(args, callback) {
var results;
//do stuff and populate results.
callback(results);
}
getResults(args, someFunction);
Except you don't have the issue of trying to wait for async stuff to happen, which you can't do, without weird logic.

Writing async http returns in Nodejs

I realize this quesiton probably gets asked a million times but I'll try anyway. So I am used to Python and Ruby and 'blocking' imperative code blocks and objects and methods and trying to learn this newfangled Node thing for a project I joined. Try as I might, I can't quite wrap my head around async callbacks and passing return values.
Here's my code:
var getAnHttp = function getAnHttp (args, callback) {
var req = http.request(args, callback);
req.on('error', function(errmsg) {
console.log('problem with request\t' + errmsg.message);
});
req.end();
};
var getWebPageBody = function getWebPageBody (res) {
var pageRes = "";
res.setEncoding('utf8');
res.on('data', function(requestBody) {
pageRes = requestBody;
console.log('[ DEBUG ] BODY:\t' + pageRes);
});
res.on('end', function() {
return pageRes;
});
};
exports.captureLink = function captureLink(targetLink) {
getAnHttp(targetLink, getWebPageBody);
};
And actually calling it:
var crawl = require('../grab_site');
var aGreatSite = { hostname : 'hotwebcrawlingaction.xxx',
port : 80,
path : '/asyncpron',
method : 'GET'
};
var something = crawl.captureLink(aGreatSite);
getWebPageBody will print my output, but I can't get my returns to bubble up through the funcitons. I know I'm calling something in a sync fashion that and some in async but I can't quite sort this out. While I could certainly just put this in one big function I'm trying to do this right, not hack it out.
Anyway sorry for a noob question--I feel like I'm trying to be functional and OOP+imperative at the same time--i see plenty of other examples but I'm trying not to cargo cult or hail mary this one.
Async functions will never return something that has to fetched with async. getWebPageBody in your case returns undefined, and then later your callbacks happen.
In synchronous programming you return a value. But in async, you provide it as an argument to a callback function.
So instead, make your function accept a callback argument, and simply call it when you are done.
var getWebPageBody = function(res, callback) {
var pageRes = "";
res.setEncoding('utf8');
res.on('data', function(requestBody) {
pageRes = requestBody;
console.log('[ DEBUG ] BODY:\t' + pageRes);
});
res.on('end', function() {
callback(pageRes); // invoke callback
});
};
// and call it
getWebPageBody(res, function(pageRes) {
// pageRes is now the thing you expect, inside this function.
});
If you invoke a function which triggered async actions, return will never get any values out of that. It's all about callbacks. You fire your own callback, from the callback of something else.

Invoking async.series inside async.series produces unpredictable output

Using caolan's async library for node.js, I've been trying to call a function that uses async.series inside another function that uses async.series, but I still can't get the functions to run in the correct order, as detailed below:
The terminal output shows the second function being called before the first, for no apparent reason:
The "sys" module is now called "util". It should have a similar interface.
Starting the second step in the series
Value of b: undefined
Invoking the function firstStep
the value of toObtain is: [object Object]
And here's the corresponding source code:
var im = require('imagemagick');
var async = require('async');
var toObtain;
var b;
async.series([
function (callback) {
//It appears that this function is being invoked after the second function.
//Why is this happening?
firstStep();
callback();
},
function (callback) {
//Why is the output of this function being displayed BEFORE the output of the function above? It's the opposite of the order in which I'm calling the functions.
console.log("Starting the second step in the series");
console.log("Value of b: " + b);
}]);
function firstStep(){
async.series([
function (next) { // step one - call the function that sets toObtain
im.identify('kittens.png', function (err, features) {
if (err) throw err;
console.log("Invoking the function firstStep");
toObtain = features;
//console.log(toObtain);
b = toObtain.height;
next(); // invoke the callback provided by async
});
},
function (next) { // step two - display it
console.log('the value of toObtain is: %s',toObtain.toString());
}]);
}
After about an hour of experimentation, I got it to work properly. I simply modified the firstStep function so that it takes a callback function as a parameter, and calls the callback at the end of the firstStep function.
var im = require('imagemagick');
var async = require('async');
var toObtain = false;
var b;
async.series([
function (callback) {
firstStep(callback); //the firstStep function takes a callback parameter and calls the callback when it finishes running. Now everything seems to be working as intended.
},
function (callback) {
console.log("Starting the second step in the series");
console.log("Value of b: " + b);
}]);
function firstStep(theCallback){
async.series([
function (next) { // step one - call the function that sets toObtain
im.identify('kittens.png', function (err, features) {
if (err) throw err;
console.log("Invoking the function firstStep");
toObtain = features;
//console.log(toObtain);
b = toObtain.height;
next(); // invoke the callback provided by async
});
},
function (next) { // step two - display it
console.log('the value of toObtain is: %s',toObtain.toString());
theCallback();
}]);
}

Resources