Sequential execution in node.js - node.js

I have code like
common.findOne('list', {'listId': parseInt(request.params. istId)}, function(err, result){
if(err) {
console.log(err);
}
else {
var tArr = new Array();
if(result.tasks) {
var tasks = result.tasks;
for(var i in tasks) {
console.log(tasks[i]);
common.findOne('tasks', {'taskId':parseInt(tasks[i])}, function(err,res){
tArr[i] = res;
console.log(res);
});
}
console.log(tArr);
}
return response.send(result);
}
});
It is not executed sequentially in node.js so I get an empty array at the end of execution. Problem is it will first execute console.log(tArr); and then execute
common.findOne('tasks',{'taskId':parseInt(tasks[i])},function(err,res){
tArr[i] = res;
console.log(res);
});
Is there any mistake in my code or any other way for doing this.
Thanks!

As you are probably aware, things run asynchronously in node.js. So when you need to get things to run in a certain order you need to make use of a control library or basically implement it yourself.
I highly suggest you take a look at async, as it will easily allow you to do something like this:
var async = require('async');
// ..
if(result.tasks) {
async.forEach(result.tasks, processEachTask, afterAllTasks);
function processEachTask(task, callback) {
console.log(task);
common.findOne('tasks', {'taskId':parseInt(task)}, function(err,res) {
tArr.push(res); // NOTE: Assuming order does not matter here
console.log(res);
callback(err);
});
}
function afterAllTasks(err) {
console.log(tArr);
}
}
The main things to see here is that processEachTask gets called with each task, in parallel, so the order is not guaranteed. To mark that the task has been processed, you will call callback in the anonymous function from findOne. This allows you to do more async work in processEachTask but still manage to signify when it is done. When every task is done, it will then call afterAllTasks.
Take a look at async to see all the helper functions that it provides, it is very useful!

I've recently created a simple abstraction named "wait.for" to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor
Using wait.for and async your code will be:
var wait = require('waitfor');
...
//execute in a fiber
function handleRequest(request,response){
try{
...
var result = wait.for(common.findOne,'list',{'listId': parseInt(request.params.istId)});
var tArr = new Array();
if(result.tasks) {
var tasks = result.tasks;
for(var i in tasks){
console.log(tasks[i]);
var res=wait.for(common.findOne,'tasks',{'taskId':parseInt(tasks[i])});
tArr[i] = res;
console.log(res);
}
console.log(tArr);
return response.send(result);
};
....
}
catch(err){
// handle errors
return response.end(err.message);
}
};
// express framework
app.get('/posts', function(req, res) {
// handle request in a Fiber, keep node spinning
wait.launchFiber(handleRequest,req,res);
});

Related

rethinkdb & nodejs: save result in var

it's possible save result query of rethinkdb in a variable?
Like this??
var test = r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run()
now I use this method
var test;
r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run().then(function(response){
test = response;
})
If you don't like using promises and are using the latest version of ECMAScript, you can use async/await, which provides syntactic sugar to let you write your asynchronous code as if it were synchronous.
You could rewrite your example like this:
async function getTest() {
var test = await r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run();
return test;
}
Note that “behind the scenes”, this still uses promises, but it makes the code easier to read and understand.
Simplest yet working solution would be as bellow, using callback
function getTest(callback) { // add callback
r.db('chat')
.table('group_chat')
.count(r.row('passengers')) // you forgot closing brace here
.contains(function(passeggers) {
return passeggers('nome').eq('pigi')
})
.run()
.then(function(result) {
callback(null, result); // call callback with result
})
.error(function(err) {
callback(err, null); // call callback with error
});
}
getTest(function(err, result) { // invoke callback
if (err) throw err;
console.log(result)
var test = result; // note: you can use test variable only inside this call
})

Synchronous request with mysql query in nodejs

I am working on node.js with express framework and I am trying to call multiple mysql queries and each query depend upon the previous queries.
How can be execute query in synchronously.
function f1(id, cb) {
$sql = "SELECT * FROM s1 where process_id=" +id;
connection.query(
$sql,
function (err, result) {
if (err) {
cb(err, null);
} else {
var str = '';
if (result.length > 0) {
for(val in result) {
$sql = "SELECT attribute_name FROM s2 where id=" + result[val].id;
connection.query(
$sql,
function (err, attrresult) {
if (err) {
cb(err, null);
} else {
if (result.length > 0) {
str += attrresult[0].attribute_name;
}
}
}
);
}
}
cb('', str);
}
}
);
}
router.get('/', function(req, res, next) {
f1('27', function (err,respose) {
console.log(respose);
});
});
Please suggest. How can we do this.
Thanks in advance.
you can use promise chaining, or async package to handle series execution, step by step
check the below guide for promise chaining
https://coderwall.com/p/ijy61g/promise-chains-with-node-js
for async check the following package
https://github.com/caolan/async
Node I/O is async by definition. I think your problem is the for loop. It loops all the iterations before the matching-per-variable nested query callback. So use some mechanism to achieve the desired flow of execution. You can use promises, there are several good libs(Q,Bluebird,native promises with ES2015...) Also you can use async.js wich is easier to deal with it.
The libs are not mandatory but they do the work easier.
As everybody said, Async.js is a nice solution to do this kind of thing.
However it could be a little hard to handle at the beginning. If you like to have a little more abstraction, I would suggest you to use a framework like Danf (build upon Express). This framework abstracts Async.js to handle asynchronicity (execute operations in series, in parallel, ...) in an original and simple way. Take a look at the overview to understand what I mean.
You can't really make the synchronous, but you can make then look like sync code by making use of promises and generators.
function mySexyMethod() {
return new Promise(function (resolve, reject) {
someAsyncethod(params, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
})
});
}
Express router
var wrap = require('co-express');
router.verb('some-route', wrap(function* (req, res, next) {
var val, val2;
try {
val = yield mySexyMethod();
val2 = yield anotherPromiseThatRequiresPreviousVal(val);
} catch (e) {
return next(e);
}
});
Even better, look into https://www.npmjs.com/package/bluebird and check if whatever mysql lib you are using can be promisified.

node.js callback function at the after loop has ended

I have an array of URLs and I want to loop through them and fetch thr content. After I have looped through them and fetched thr content I want a callback function to be called.
I know I can do this via async library but I want to do this without using any library.
Sample of what kind of code I want is below
['yahoo.com', 'gmail.com'].each(function(item){
//code to fetch URL content
},someCallbackFunctionToBeExecutedAtTheEndOfLoop);
This is typically the type of thing you do using promises (But you would need a library), with a code like:
var ops = [];
urls.forEach(function(url) {
ops.push(fetchUrl(url));
});
P.all(ops).then(callback);
function fetchUrl(url) {
var defer = P.defer();
//do stuff
// call defer.resolve(result);
return defer.promise;
}
If you don't want to use promises, you can use a counter of operations, like:
var ops = urls.length;
urls.forEach(function(url) {
// do stuff
ops--;
if (ops === 0) {
callback();
}
});
If you chose the promises, I advice to use p-promise module, which is far more optimized than Q.
If you want to do it without any sort of library like async, then you have to write your own counter to keep track of when all the async responses have been completed:
var request = require('request');
function loadAll(list, fn) {
var cnt = list.length;
var responses = [];
list.forEach(function(url, index) {
request(url, function(error, response, body) {
if (error) {
fn(error);
} else {
responses[index] = response;
--cnt;
if (cnt === 0) {
fn(0, responses);
}
}
});
})
}
loadAll(['http://www.yahoo.com', 'http://www.gmail.com'], function(err, results) {
if (!err) {
// process results array here
}
});
If you're going to be doing many async operations in node.js, then getting a promise library like Bluebird will save you a lot of time. For example, I think you could do the above in something like this (untested):
var Promise = require("bluebird");
var requestP = Promise.promisfy(require("request"));
Promise.map(['http://www.yahoo.com', 'http://www.gmail.com'], requestP).then(function(results) {
// process the array of results here
});

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.

How to deal with promises in loop?

This is what I would like to do
var response = [];
Model.find().then(function(results){
for(r in results){
MyService.getAnotherModel(results[r]).then(function(magic){
response.push(magic);
});
}
});
//when finished
res.send(response, 200);
however it returns just [] because the async stuff is not ready yet. I am using sails.js that uses Q promise. Any ideas how to return a response when all async calls are finished?
https://github.com/balderdashy/waterline#query-methods (promise methods)
Since waterline uses Q, you can use the allSettled method.
You can find more details on Q documentation.
Model.find().then(function(results) {
var promises = [];
for (r in results){
promises.push(MyService.getAnotherModel(results[r]));
}
// Wait until all promises resolve
Q.allSettled(promises).then(function(result) {
// Send the response
res.send(result, 200);
});
});
You simply can't do that, you have to wait for the asynchronous functions to complete.
You can either create something yourself, or use the async middleware, or use built in features, as noted in Florent's answer, but I'll add the other two here anyway :
var response = [];
Model.find().then(function(results){
var length = Object.keys(results).length,
i = 0;
for(r in results){
MyService.getAnotherModel(results[r]).then(function(magic){
response.push(magic);
i++;
if (i == length) {
// all done
res.send(response, 200);
}
});
}
});
or with async
var response = [];
Model.find().then(function(results){
var asyncs = [];
for(r in results){
asyncs.push(function(callback) {
MyService.getAnotherModel(results[r]).then(function(magic){
response.push(magic);
callback();
})
});
}
async.series(asyncs, function(err) {
if (!err) {
res.send(response, 200);
}
});
});
Take a look at jQuery deferred objects:
http://api.jquery.com/category/deferred-object/
Specifically, .when()
http://api.jquery.com/jQuery.when/

Resources