I'm facing an issue regarding callback in Request js function. Given below is my code.
function getContent(address, result, callback){
request(address, function (err, response, body) {
if(err) throw err;
if (response.statusCode == 200) {
console.log(body);
}
});
callback(null, result);
}
Now when i run given code my callback is called and then my request function is hit. I want to execute my callback after execution of console.log(body) line. Kindly give me your suggestions about this issue.
Thanks in advance.
The callback() function should be inside the callback for the request. That ways, only when the request is completed would it get called.
function getContent(address, result, callback){
request(address, function (err, response, body) {
if(err) throw err;
if (response.statusCode == 200) {
console.log(body);
callback(null, result);
}
});
}
Related
I need to make a function like this.
function getDataFromCollection(collectionName) {
let data;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
db.collection(collectionName).find({}).toArray(function(err, result) {
data = result;
console.log(result);
db.close();
});
});
return data;
}
The problem is that data is undefined, but when I execute console.log(result), it works. Any idea to help me. Thanks in advance.
There's a very simple explanation. The function(err, result) is essentially asynchronous and is not called immediately but after some time when the data is fetched from mongo. The function(err, result) is thus a callback. So, data is not set to result immediately but after a while. Now, you return data immediately and don't wait for it to be populated (inside the function(err, result) callback) so undefined is obviously returned.
The solution would be to use JavaScript's Promises which lets you use asynchronous code and callbacks. We return a Promise from getDataFromCollection and chain a .then when we call it. The function or callback that is passed to the then is executed when the promise is resolved inside the getDataFromCollectionfunction with the data that was passed to the resolve function. Thus, the callback inside then would be called when you receive the result.
All the code -
function getDataFromCollection(collectionName) {
return new Promise(function(resolve, reject) {
MongoClient.connect(url, function(err, db) {
if (err) {
reject(err);
return;
}
db.collection(collectionName).find({}).toArray(function(err, result) {
if (err) {
reject(err);
return;
}
console.log(result);
db.close();
resolve(result);
});
});
});
}
Consume the function like so.
getDataFromCollection("collection")
.then(function(result) {
// use result
})
.catch(function(err) {
console.log(err);
});
Read up about Promises from here.
I am trying to do a waterfall async but i don't get the expected output that i want.
Basically my waterfall works as expected if i use an array instead of the query
so i guess i am doing something wrong on the callback of the query but i don't know what.
Code when it works with what i expect using array:
function range(start, end) {
var foo = [];
for (var i = start; i <= end; i++) {
foo.push(i);
}
return foo;
}
users = range(1,2)
obj = [1,2];
async.forEachLimit(users, 1, function(user, userCallback){
async.waterfall(
[
function(callback) { // query the data to get the category and specific number of rows
results = {sku_config:'A',img:'http//blabla',sku_config:'B',img:'http//bloblo'}
callback(null, results);
},
function(obj,callback) {
async.eachSeries(obj, function (sku, callback) {
var url = sku.img;
var sku = sku.sku_config;
console.log("loop");
request.get(url, {encoding: null} , function(error, response, body) {
console.log('request');
});
callback(null);
}, function(responsetoendofloop){
callback(null);
});
},
],
function (err) {
console.log('Finish');
userCallback(null);
}
);
}, function(err){
console.log("User For Loop Completed");
});
output:
loop
request
loop
request
Finish
loop
request
loop
request
Finish
User For Loop Completed
But when i try to query the data with mysql here comes the problem
code:
async.forEachLimit(users, 1, function(user, userCallback){
async.waterfall(
[
function(callback) { // query the data to get the category and specific number of rows
connection.query(query_sku,
['Fashion',1,2],
function(err, results, fields) {
if (err)
throw err;
callback(null, results);
});
},
function(obj,callback) {
async.eachSeries(obj, function (sku, callback) {
var url = sku.img;
var sku = sku.sku_config;
console.log("loop");
request.get(url, {encoding: null} , function(error, response, body) {
console.log('request');
});
callback(null);
}, function(responsetoendofloop){
callback(null);
});
},
],
function (err) {
console.log('Finish');
userCallback(null);
}
);
}, function(err){
console.log("User For Loop Completed");
});
output:
loop
loop
Finish
loop
loop
Finish
User For Loop Completed
request
request
request
request
All the request gets executed at the end :(
If you have idea on what i could fix.
Thanks
The first problem you have is that your callbacks have the exact same name, this could cause major problems. The callbacks you are meaning to call can not be differentiated, which could cause your program to execute pieces of code that shouldn't be executed until later.
The second problem is that the callback is placed outside of the request.get function. The nature of node js means that it does not wait until the request.get function returns and instead just calls the callback straight away. By placing the callback inside of the request.get function it is forced to wait until the request function returns and then the callback is called. A revised version of your code is below.
async.forEachLimit(users, 1, function(user, userCallback){
async.waterfall(
[
function(callback) { // query the data to get the category and specific number of rows
connection.query(query_sku,
['Fashion',1,2],
function(err, results, fields) {
if (err)
throw err;
callback(null, results);
});
},
function(obj,callback) {
async.eachSeries(obj, function (sku, seriesCallback) {
var url = sku.img;
var sku = sku.sku_config;
console.log("loop");
request.get(url, {encoding: null} , function(error, response, body) {
console.log('request');
seriesCallback(null);
});
}, function(responsetoendofloop){
callback(null);
});
},
],
function (err) {
console.log('Finish');
userCallback(null);
});
}, function(err){
console.log("User For Loop Completed");
});
Your callback(null); inside async.eachSeries are after request.
To fix just put inside request like this.
request.get(url, {encoding: null} , function(error, response, body) {
console.log('request');
callback(null);
});
Plus to be clear what you actually calling rename callback functions. For example callback inside eachSeries call next
function(obj,callback) {
async.eachSeries(obj, function (sku, next) {
var url = sku.img;
var sku = sku.sku_config;
console.log("loop");
request.get(url, {encoding: null} , function(error, response, body) {
console.log('request');
next(null);
});
}, function(responsetoendofloop){
callback(null);
});
}
Hope this helps.
I know this kind of error handling is not right, promises should be used instead, but I am wondering if it could work as it is:
router.get('/main', function(req, res, next) {
var myCallback = new function(err, data){
if(err) {
res.status(500).send({ error: "Error (best handling ever)" });
return;
}
res.send("Success");
return;
};
mainProcess(myCallback);
});
function mainProcess(callback){
request.post(requestParams, function(error, response, body) {
if (error) {
console.log(error.message);
callback.return(error, "");
} else {
request.post(requestParams, function(error, response, body) {
if (error) {
console.log(error.message);
callback.return(error, "");
} else {
// Success
callback.return(null, "Success");
}
});
}
});
}
I could test it myself, but I need to know whether callback that was passed as a parameter could be used in nested functions and whether it's the right approach.
I the following code in my node.js project.
async.eachLimit(dbresult, 1, function (record, callback) {
var json = JSON.stringify(record)
var form = new FormData()
form.append('data', json)
form.submit(cfg.server + '/external/api', function (err, res) {
if (err) {
callback(err)
}
if (res.statusCode === 200) {
connection.query('UPDATE selected_photos set synced = 1 WHERE selected_id = "' + record.selected_id + '"', function (err, result) {
if (err) {
console.log(err)
callback(err)
} else {
callback()
}
})
} else {
console.log(res.statusCode)
return callback(err)
}
})
}, function (err) {
// if any of the file processing produced an error, err would equal that error
if (err) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A share failed to process. Try rerunning the Offline Sync')
process.exit(0)
} else {
console.log('All files have been processed successfully')
process.exit(0)
}
})
}
res.statusCode = 302 So this should error out. But the the error callback is never triggered. How do it get it to trigger the error so that it stops eachLimit and the shows the
console.log('A share failed to process. Try rerunning the Offline Sync')
You have:
if (err) {
in first line of form submit handler. After that, you are sure that there was no error. So when you check response statusCode and try to call back with error, you are calling back with empty value.
That is why you do not get error when checking for it in your final callback function.
Try to create new Error('Status not OK: ' + res.statusCode) when calling back from your form submit handler.
I am calling function dorequest many times per request to node server.
I have problem with request to webpage running on apache2.2.21. Almost of these request are done without any problems, but several request ending with error ECONNRESET and I don't know why. If I use apapche2.4 then everything going well.
var request = require('request');
function dorequest(set, callback){
request.get(url, function optionalCallback(err, httpResponse, body){
if (err){
console.log(url);
throw err;
} else {
//do some stuffs
}
});
}
Probably your apache server simply drops your request because there are too many connections at the same time initiated by dorequest function.
You can execute those request consequently by calling one in the callback of another by calling the next request in the callback for the previous one, but since there are quite a lot of them and for estetic reasons I would recommend to use async library - it's awesome and really handy when dealing with things like that.
function dorequest(set, callback){
request.get(url, function optionalCallback(err, httpResponse, body){
if (err){
callback(err);
} else {
//do some stuffs
}
callback(err, res);
});
}
var maxRequestAtATime = 30;
async.mapLimit(arrayOfOptions, maxRequestAtATime, dorequest, function(err, results){
// results is now an array of stats for each request
});
If the options of a request depend on the options of the previous one, you should use async.waterfall.
I updated script and use async.queue function for that and still have some err on apache.
function dorequest(set, callback)
{
console.log('add request');
q.push({set: set, callback: callback}, function (err) { });
}
var q = async.queue(function (task, callback) {
setTimeout(function () {
console.log('hello ' + task.set.url, ' lenght: ',q.length());
if (task.set.method=='get')
{
myrequest.get(task.set.url, function optionalCallback(err, httpResponse, body)
{
if (err)
{
console.log(task.set.url);
throw err;
}
else
{
//console.log(set.url,body);
if (typeof task.callback !='undefined') task.callback(body);
callback();
}
});
}
else
{
if (!task.set.data) task.set.data={};
myrequest.post(task.set.url, function optionalCallback(err, httpResponse, body)
{
if (err)
{
console.log(task.set.url);
throw err;
}
else
{
//console.log(set.url,body);
if (typeof task.callback !='undefined') task.callback(body);
callback();
}
}).form(task.set.data);
}
},500);
},1);