NodeJS Async: callback allready called? - javascript

I am getting this error:
node:19100) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called.
On my async.each call, it seems like it is trying to call "done()" more then once per "circuit" but I don't understand why, i though that once the async callback is called the function would exit ?
Circuits is an array of String containing ids. I am simply trying to loop through them to execute async calls to database on each.
var getTimeseriesForCircuit = function(circuits, to, from, callback){
if (!validateDates(from, to)) {
return callback(400, 'Invalid date(s)');
}
var validJSON = false;
try {
circuits = JSON.parse(circuits);
validJSON = true;
}
catch (e) {
return callback(500, e);
}
if (validJSON) {
async.each(circuits, function (circuitID, done) {
var frequency = getFrequencyFromRange(from, to);
var influxFromDate = from * 1000000;
var influxToDate = to * 1000000;
getVoltageGatewayID(null, circuitID, function (gatewayID) {
getVoltageFromInflux(null, influxFromDate, influxToDate, gatewayID, frequency, function (voltage) {
getMeanAmpsFromInflux(null, influxFromDate, influxToDate, circuitID, frequency, function (data) {
if (JSON.stringify(data) != []) {
var timeWithPower = calculatePower(data, voltage);
return done(null, {'circuitID': circuitID, data: timeWithPower});
}
});
});
});
}, function (err, results) {
if (err) {
return callback(500, err)
} else {
return callback(200, results)
}
});
}
else {
return callback(400, 'The circuits sent were not in a valid format');
}
}

I think you have to call your async callback "done" without return:
done(null, {'circuitID': circuitID, data: timeWithPower});
and on error something like this:
done('errormessage');
so you get your result in the "final"callback after your each
see async

I think you missing return statement in function.
When you catch or have an error instead of just callback() use return callback().
This will prevent execution of code bellow return statements and error that you see.
Hope this helps.

Related

How to update an array data in database using NodeJs Async?

I am new to NodeJs and I'm finding the Non Blocking and Asynchronous nature of JS extremely difficult to understand and handle,
I have a piece of code which is supposed to Iterate an array
and for every iteration, I'm supposed to make a DB update.
Can someone provide the correct implementation of Async library functions and help fix my code?
Code example -
function updateFunction(conn, requestBody, callback) {
let arr = [];
async.each(requestBody.arr, function(item, callback) {
let sqlData = []
let columns = "";
if(item.columnData != null){
sqlData.push(item.columnData);
columns += "`columnName` = ?,";
}
if(columns != ''){
columns = columns.substring(0,columns.length-1);
let sqlQuery = 'UPDATE someTable SET '+columns
+' WHERE id = "' + item.id + '"';
conn.query(sqlQuery, sqlData, function (err, result) {
if (err) {
return callback(err, false);
}
})
}
else{
return callback(null, false);
}
columns = "";
sqlData = [];
},
function(err, results) {
//Code never reaches here, don't know why
if (err) {
return callback(err, false);
}
else{
return callback(null, true);
}
});
} // END
During your database query call, on a successful query your callback is not called, therefore causing your code to never reach the final callback.
You will want to add another return statement after your if (err) { return callback(err); } to let async know your database query is finished.
And another thing, according to the docs, the async each method's final callback does not invoke with results in its callback.
A callback which is called when all iteratee functions have finished, or an error occurs. Invoked with (err).
Therefore, it is not required for you to pass a value into the callback statement within your iteratee function.
Modify your code to do this and it will work.
conn.query(sqlQuery, sqlData, function (err, result) {
if (err) {
return callback(err);
}
return callback(null);
})
Hope this helps.
conn.query(sqlQuery, sqlData, async function (err, result) {
if (err) {
return await callback(err, false);
}
})
Something like this.. so the function callback is async here and we gave await which actually waits until the return call is finished..

Series control flow with bluebird promises

I have a number of promises and I want to execute them in order, but conditionally.
For example, I have the following promises:
getItems()
getItemsSource()
getItemsAlternativeSource()
What I want to do is try getItems() first. If this resolves with an empty value OR if it throws an error, I want to log that error (if that's the case), but then try getItemsSource(), same as above, if it resolves with no value or throws an error, I want to log the error if that's the case and try getItemsAlternativeSource().
I know I can do this conditionally, in each then() or catch(), but that seems a bit redundant. Is there a better way to handle this kind of control flow?
Thank!
You can use an empty value as the return value of the catch handler:
getItems().catch(function(err) {
console.warn(err);
return null; // <==
}).then(function(items) {
if (items) return items;
else return getItemsSource().catch(function(err) {
console.warn(err);
return null; // <==
}).then(function(sourceitems) {
if (items) return items;
else return getItemsAlternativeSource().catch(function(err) {
console.warn(err);
throw new Error("items couldn't be fetched normally, from source, or from alternative source");
});
});
});
If you absolutely want to avoid duplication, you can use this highly abstract approach:
var tryAll = [getItems, getItemsSource, getItemsAlternativeSource].reduceRight(function(nextAlternative, fetch) {
return function() {
return fetch().then(function(items) {
if (items) return items;
else return nextAlternative(); // now we can even call it in two locations
}, function(err) {
console.warn(err);
return nextAlternative(); // without having to resort to catch-then
});
};
}, function last() {
throw new Error("items couldn't be fetched normally, from source, or from alternative source");
});
tryAll();
I'd suggest you create a function that takes an array of functions that will call each function in the array until one returns with some data.
function getFirstData(array) {
var index = 0;
function next() {
if (index < array.length) {
return array[index++]().then(function(data) {
// if we got an answer, return it as the resolve value
if (data) return data;
// otherwise, reject so we go to the next one
return Promise.reject(null);
}).catch(function(err) {
if (err) console.err(err);
return next();
});
} else {
// got to the end of the array without a value
throw new Error("No data found");
}
}
return Promise.resolve().then(next);
}
var fns = [getItem, getItemsSource, getItemsAlternativeSource];
getFirstData(fns).then(function(data) {
// got data here
}).catch(function(err) {
// no data found here
});
If you want the functions to have arguments, then you can .bind() the arguments to the functions before putting them in the array.
And, here's a different implementation using .reduce() to traverse the array:
function getFirstData(array) {
return array.reduce(function(p, fn) {
return p.then(function(priorData) {
// if we already got some data, then just return it
// don't execute any more functions
if (priorData) return priorData;
return fn().catch(function(err) {
console.log(err);
return null;
});
});
}, Promise.resolve()).then(function(data) {
if (!data) {
throw new Error("No data found");
}
});
}

Run code after function completes and get returned value

Imagine i have a simple javascript function:
function someFunction(integer)
{
data = integer + 1;
return data;
}
I need to call this from inside another function and use the returned value:
function anotherFunction(integer)
{
int_plus_one = someFunction(integer);
//Do something with the returned data...
int_plus_two = int_plus_one + 1;
return int_plus_two;
}
How can i ensure that the return of anotherFunction return is only returned after someFunction completes? It actually seems to work ok with very fast functions like these. However if someFunction has to do some ajax lookups, the return of aotherFunction fails.
Thanks,
Steve
You do not know when or even if an asynchronous function will complete. The only way to handle this is to use a callback function, a function that gets executed after the async operation has completed.
This was my "aha!" moment: How to return the response from an asynchronous call?
As far as your code is sync, the approach above is fine.
Once you start introducing async parts, the one below involving callbacks is a common used approach:
function fn (v, cb) {
doSomethingAsyncWithV(function (err, _v) {
if(err) return cb(err);
cb(null, _v);
})
}
function yourFirstFn () {
var v = 0;
fn(v, function (err, _v) {
// do here whatever you want with the asynchronously computed value
});
}
How about promise? With that in mind, there's no need to worry about callback. It's one of the cool things in AngularJS.
var q = require('q');
var myPromise =function() {
var deferred = q.defer();
setTimeout(function(){
var output = anotherFunction(1);
deferred.resolve(output)
}, 10000); // take times to compute!!!
return deferred.promise;
}
var objPromise = myPromise();
objPromise.then(function(outputVal){
console.log(outputVal) ; // your output value from anotherFunction
}).catch(function(reason) {
console.log('Error: ' + reason);
})
then is ONLY exeucted after promise has been resolved. If an exception or error is caught, the catch function executes.
how about this?
function someFunction(integer, callback)
{
data = integer + 1;
return callback(data);
}
function anotherFunction(integer)
{
int_plus_one = someFunction(integer, function(data){
int_plus_two = int_plus_one + 1;
return int_plus_two;
});
//Do something with the returned data...
}
You could use promises:
new Promise(function someFunction(resolve, reject) {
ajaxLib.get(url, options, function (data) {
resolve(data);
});
}).then(function anotherFunction(integer)
{
int_plus_one = integer;
//Do something with the returned data...
int_plus_two = int_plus_one + 1;
return int_plus_two;
});
If you use jQuery, $.ajax returns a thenable :
$.ajax(url, options).then(function processDataFromXHR(data) {
return data.integer;
}).then(function anotherFunction(integer){
int_plus_one = integer;
//Do something with the returned data...
int_plus_two = int_plus_one + 1;
return int_plus_two;
});

Extract value from double callback

How can I assign value to variable in global from double callback?
First of, I read some value from file, when its done, I pass it to some fn in callback and want to use result value in initial scope, outside callback.
I can't wrap my head around this for some reason although at first it looks trivial.
var done = function(err, value) {
if (err) {
return;
}
var resultValue = someMethod(value);
};
loadFile(done);
var resultVal = ?? //result value needed here
function loadFile(done) {
fs.realpath(filePath, function (err, resolvedPath) {
if (err) {
return done(err);
}
fs.readFile(resolvedPath, function (err, value) {
if (err) {
return done(err);
}
return done(null, data);
});
});
}
As I said in my comment you are using an asynchronous call to load a file. You want the result of someMethod stored into the global variable resultVal. Except this isn't possible.
When you call loadFile(done) a asynchronous call is made to the server. This call is being resolved by an event. If the event returns 200 the server returned the expected answer. If their is an error it will be passed to done, if not the data will be passed. Let's say this takes about 250 ms to resolve.
In the mean time JavaScript continued parsing the code, because the call was asynchronous, running in a separate thread, thus not halting the execution of the main thread. The next line that gets parsed is returnVal. However the call isn't resolved yet because this line gets executed 1 ms after the function loadFile was called. This leaves a gap of 249 ms.
The solution is to rethink your code to cope with the asynchronous call.
var done = function(err, value) {
if (err) {
return;
}
var resultValue = callBack(value);
};
loadFile(done);
function someMethod(value)
{
//execute whatever you want to do here!
}
function loadFile(done) {
fs.realpath(filePath, function (err, resolvedPath) {
if (err) {
return done(err);
}
fs.readFile(resolvedPath, function (err, value) {
if (err) {
return done(err);
}
return done(null, data);
});
});
}
Of course you can provide the function done with the callback you want. Just look at this code:
var done = function(err, value, callBack) {
if (err) {
return;
}
var resultValue = someMethod(value);
};
loadFile(done, method1);
function method1(value)
{
//execute whatever you want to do here!
}
function loadFile(done, callBack) {
fs.realpath(filePath, function (err, resolvedPath) {
if (err) {
return done(err);
}
fs.readFile(resolvedPath, function (err, value) {
if (err) {
return done(err);
}
return done(null, data, callBack);
});
});
}
Instead of declaring resultValue as : var resultValue = someMethod(value);
You can do global.resultValue = someMethod(value);
This will make resultValue as a global variable.
You can access it anywhere using global.resultValue.
Similarly,instead of using global you can also use process.
global and process are global objects for nodejs just like window is for javascript.

Returning from anonymous function passed as parameter

Consider the following code:
function dbTask(q) {
mysql = new MySQL();
mysql.host = sqlHost;
mysql.user = sqlUser;
mysql.password = sqlPassword;
mysql.query("USE stock");
return mysql.query(q, function(err, results, fields) {
if(err) {
console.log("MySQL Error: " + err + ", Query: " + q);
return false;
} else {
return results; //here
}
});
};
var r = dbTask("SELECT * FROM user;");
console.log(r);
Whereas, I want the results to be returned from the inner anonymous function when calling dbTask() in the second last line, I am getting different output which seems like some internal construct of the mysql library under use.
How can I get dbTask to return the results when called?
Since mysql.query is asynchronous, then you'll have to re-think your architecture.
Instead of having your function return true or false, you'll have to pass in handlers to be called if the query returned true or false.
Something like this:
function dbTask(q, success, failure) {
mysql = new MySQL();
mysql.host = sqlHost;
mysql.user = sqlUser;
mysql.password = sqlPassword;
mysql.query("USE stock");
mysql.query(q, function(err, results, fields) {
if(err) {
console.log("MySQL Error: " + err + ", Query: " + q);
failure(err, results, fields);
} else {
success(results, fields);
}
});
};
Which you'd call like this:
dbTask(q,
function(results, fields) { /* ... */ },
function(err, results, fields) { /* ... */ });
You can't because dbTask returns once the mysql.query call completes to initiate the query. So by the time mysql.query's callback is called, console.log(r) has already executed.
This is the crux of the asynchronous nature of node.js.
What you can do is have dbTask accept a callback parameter that the function calls once results is available so that it can be provided to the caller asynchronously.

Categories

Resources