I can't find a proper explanation of how to use the retry function from the async librarydocs
var async = require('async');
function callFunc(data, time, name, callback) {
console.log("#")
callback({message: data, time, name}, null); //error
// callback(null, {message: "ok"}); // ok
}
var func = callFunc.bind(null, "data", "time", "name", function (err, data) {
console.log(data);
return err;
})
async.retry({times: 3, interval: 1000}, func, function (err, results) {
console.log('===================================');
console.log('Async function');
})
Example of what I implement(but simpler). Can you tell me what I'm doing wrong? Killed the whole day for this.
P.S. The function should be called three times on error.
The async.retry function expects a function that has the signature function (callback, results), where callback is a callback function that you should call when the operation is complete, and results is an object that contains the results of the operation so far.
var async = require('async');
function callFunc(data, time,callback) {
console.log(data, time)
callback({message: "err"}, null); // error
// callback(null, {message: "ok"}); // ok
}
async.retry({times: 3, interval: 1000}, function(callback, results) {
callFunc("test", "data", callback)
},
function (err, results) {
console.log('===================================');
console.log('Async function');
})
Related
So I have this code:
module.exports.getEstimate = (event, context, callback) => {
var data = JSON.parse(event.body);
lalamove.getQuotation(data ,context, function(err, llm_data){
callback(null,llm_data)
});
};
So it calls lalamove.getQuotation function and returns an object:
{ "totalFee": "108", "totalFeeCurrency": "PHP" }
Now, I have added a new function, that returns this object:
{ "totalFee": "10", "totalFeeCurrency": "PHP" }
from a different function so I thought I should push them in one array and then that is when I would call the callback but it does not work, this is what I have tried
module.exports.getEstimate = (event, context, callback) => {
var data = JSON.parse(event.body);
var response = []
lalamove.getQuotation(data ,context, function(err, llm_data){
const llm_obj = { "lalamove": llm_data }
response.push(llm_obj);
});
inhouse.getQuotation(data ,context, function(err, ih_data){
const ih_obj = {"inhouse": ih_data }
response.push(ih_obj);
});
callback(null,response);
};
and what I want to be the response is like this:
["lalamove": { "totalFee": "108", "totalFeeCurrency": "PHP" },
"inhouse": { "totalFee": "10", "totalFeeCurrency": "PHP" }]
what am I doing wrong?
Your callback(null,response) will not wait for those two callback functions to finish. You can use Promise and use Promise.all(objs).then(function) to wait for all promises finish and run.
Welcome to World's Javascript world - Callback hell.
We have some options for your case: Callback hell, async lib, Promise, async/await...
Callback hell: Call a async function in a callback
module.exports.getEstimate = (event, context, callback) => {
var data = JSON.parse(event.body);
var response = []
lalamove.getQuotation(data, context, function (err, llm_data) {
const llm_obj = { "lalamove": llm_data }
response.push(llm_obj);
// lalamove.getQuotation done!
// call next action
inhouse.getQuotation(data, context, function (err, ih_data) {
const ih_obj = { "inhouse": ih_data }
response.push(ih_obj);
// inhouse.getQuotation done!
// call the last action
callback(null, response);
});
});
};
Async lib: async
You can use waterfall function to do actions in order, and parallel if order is not matter.
module.exports.getEstimate = (event, context, callback) => {
var data = JSON.parse(event.body);
var response = []
async.parallel([
function (next) {
lalamove.getQuotation(data, context, function (err, llm_data) {
// TODO: check err object
const llm_obj = { "lalamove": llm_data }
response.push(llm_obj);
// lalamove.getQuotation done!
// do next action
next();
});
},
function (next) {
inhouse.getQuotation(data, context, function (err, ih_data) {
const ih_obj = { "inhouse": ih_data }
response.push(ih_obj);
// inhouse.getQuotation done!
// do next action
next()
});
}
], function (err) {
// TODO: check err object
// call the last action
callback(null, response);
});
};
Try wrapping two quotation calls in Promise, then utilise Promise.all to wait for both of them to be completed, then return the result to the callback
module.exports.getEstimate = (event, context, callback) => {
let data = JSON.parse(event.body);
// wrap quotation calls in `Promise`
Promise.all([
new Promise(resolve => lalamove.getQuotation(data, context, (err, lalamove) => resolve({ lalamove }))),
new Promise(resolve => inhouse.getQuotation (data, context, (err, inhouse ) => resolve({ inhouse }))),
]).then(response => {
// return the result back to `callback`
callback(null, response);
})
};
You could also try using util.promisify and the async / await syntax.
For example:
const util = require("util");
module.exports.getEstimate = async (event, context, callback) => {
let data = JSON.parse(event.body);
try {
let response = await Promise.all([ util.promisify(lalamove.getQuotation)(data, context),
util.promisify(inhouse.getQuotation)(data, context) ]);
callback(null, response);
} catch (err) {
callback(err);
}
};
We can also do something similar, but without async / await:
const util = require("util");
const getEstimate = (event, context, callback) => {
let data = JSON.parse(event.body);
Promise.all([util.promisify(lalamove.getQuotation)(data, context),
util.promisify(inhouse.getQuotation)(data, context)])
.then(response => callback(null, response))
.catch(err => callback(err));
};
var robject=[];
async.waterfall([
function (callback) {
for(var i in serial){
Router.find({},{r_serial_no:serial[i]},function (err,routerData) {
robject = robject.concat(routerData);
});
}
console.log('Robject= '+robject); //THIS RETURNS NULL
callback(null, robject);
},
function (blogs, callback) {
res.render('index', {dispatched_data:dispatched_data });
callback(null, 'Ended..' );
}
], function (err, result) {
console.log(result);
});
this is my waterfall model, here i need to access the robject from schema.find method to outside of that method. but it always return null..
how to access that??
You have the syntax error:
for(var i in serial){
Router.find({},{r_serial_no: i},function (err,routerData) {
robject = robject.concat(routerData);
});
}
the "for" loop defines "i" as next item in the array each iteration
The problem I see here is in for...in loop. Your callback will be fired even if your process i.e. Router.find is not completed. You can try below code, It might help.
Unlike your serial object please create a array called serials.
var robject=[];
async.waterfall([
function (callback) {
async.each(serials,
function(serial, localCb){
Router.find({},{r_serial_no:serial},function (err,routerData) {
robject = robject.concat(routerData);
localCb()
});
},
function(err){
console.log('Robject= '+robject);
callback(null, robject);
}
);
},
function (blogs, callback) {
res.render('index', {dispatched_data:dispatched_data });
callback(null, 'Ended..' );
}
], function (err, result) {
console.log(result);
});
I want to store all the data fetched from the database in arr_obj, then use this variable int async.forEachLimit function. For this reason i used async.series function, everything works fine except sleep(1000), code sleeps as soon as second function of async.series is called and then gives all the result together.Being a beginner in NodeJs i don't have much idea about all this.
var sleep = require('system-sleep');
//
//
var arr_obj = [];
async.series([
function (callback) {
Service.listAllUser(req.body, function (err, data) {
if(err) return callback(err);
arr_obj = data.toJSON();
callback();
});
},
function (callback1) {
console.log(arr_obj);
async.forEachLimit(arr_obj, 1, function (item, callback) {
Quality_Service.qualityService(item, function (err, data) {
if (err) return next(err);
console.log(data);
});
sleep(1000);
callback();
});
callback1();
}
], function (err) { //This function gets called after the two tasks have called their "task callbacks"
if (err) return next(err);
res.send("okay");
});
Try to use callback inside the foreach, with setTimeout
async.forEachLimit(arr_obj, function (item, callback) {
Quality_Service.qualityService(item, function (err, data) {
if (err) return next(err);
setTimeout(callback, 1000, err);
});
});
Is there something wrong with my code?, I use async.eachSeries but my result always throw undefined.
Here my code :
async.eachSeries([1,2,3], function(data, cb) {
setTimeout(function() {
cb(null, data+1);
}, 1000);
}, function(err, result) {
console.log(err, result);
});
My log returned : null, undefined instead of null, [2,3,4]
thanks... and sorry for my terrible english XD
The second argument is called when the iteration is done and with eachSeries(), it takes only one parameter, err. If you want result, you have to use mapSeries:
async.mapSeries([1, 2, 3],
function (data, cb) {
setTimeout(function () {
cb(null, data + 1);
}, 1000);
},
function (err, result) {
console.log(result);
}
);
You can use a form of result with eachSeries() as well:
var result = [];
async.eachSeries([1,2,3], function(data, cb) {
setTimeout(function() {
result.push(data+1);
cb(null);
}, 1000);
}, function(err) {
console.log(err, result);
});
That should work, although I'm not able to test it myself at the moment.
In node js, i am using async function to get the result from another function and store it as array and return the result. But here i am getting empty json as output {}. See the comments inside code block. May i know where i am doing mistake ?
collectSearchResult: function (searchConfig, callback) {
var searchResult = {};
async.each(searchConfig.scope, function (scope, callback) {
var query = {
"query": {
"match": {
"_all": searchConfig.q
}
},
operationPath = scope.url;
this.doSearch(operationPath, query, function (err, results) {
var type = scope.type;
searchResult[type] = results;
// Here i am able to get correct output async
console.log(searchResult);
});
callback();
}.bind(this), function (err) {
// Here it is just returning empty json like {}. this function is called before this.doSearch complete its task
console.log(searchResult);
callback(err, searchResult);
});
}
collectSearchResult: function (searchConfig, callback) {
var searchResult = {};
async.each(searchConfig.scope, function (scope, callback) {
var query = {
"query": {
"match": {
"_all": searchConfig.q
}
},
operationPath = scope.url;
this.doSearch(operationPath, query, function (err, results) {
var type = scope.type;
searchResult[type] = results;
// Here i am able to get correct output async
console.log(searchResult);
//<><><><><><><>
callback(); //you need to place the callback for asynch.each
//within the callback chain of your query, else async.each
//immediately finishes before your data has arrived.
//<><><><><><><>
});
}.bind(this), function (err) {
// Here it is just returning empty json like {}. this function is called before this.doSearch complete its task
console.log(searchResult);
callback(err, searchResult);
});
}