So I'm using async, this function will output some ids and the result of the count but not "callback"
getWaitingGames: function(req,res){
var me = req.session.passport.user;
var rez=[];
console.log("meeeeeeeeee");
console.log(me);
GivenQuestion.find().where({user_id:me}).exec(function(err,data){
var tpm_id = data[0].partie_id;
console.log(tpm_id);
console.log(data);
async.each(data, function(d, callback) {
var parties = [];
if (d.partie_id != tpm_id){
console.log(d.partie_id);
parties.push(d.partie_id);
tpm_id=d.partie_id;
GivenQuestion.count().where({
partie_id: d.partie_id,
user_id: me
}).exec(function(e, countRes) {
console.log(countRes);
if (countRes==2){
rez.push(d.partie_id);
callback();
}
});
}
}, function(err) {
if (err) {
console.log(error);
}
else{
console.log("callback");
res.ok(rez);
}
});
});
},
Why is that? I cannot find want I'm doing wrong, seems to be the same as in the doc and I've used it before in the same way
Edit: yes I can put the callback after the if like you guys suggested but then I get an empty rez. Why?
Does async only works one level? (I mean ,here I'm inside 2 .exec())
There is a small problem in the code. In case of async.each method, in the second parameter which is a processing function, we have to call callback() to move to the next element. If we don't call callback() then if will never come out of function.
In your case, you are making call to callback() only if if (countRes==2), but how about other scenarios? In other scenarios async.each() will wait for callback() to process next item in the data, but since we are not calling callback() so goes waiting for it.
Solution : Make call to callback() outside of if (countRes==2). Please check below code snippet for more details:
GivenQuestion.count().where({
partie_id: d.partie_id,
user_id: me
}).exec(function(e, countRes) {
console.log(countRes);
if (countRes==2){
rez.push(d.partie_id);
}
callback();
});
Please revert in case you still find the issue.
Need two inputs to have more insight about the issue:
Did you check that the condition if (countRes==2) results to true? Because if this condition evaluates to false, rez will always be empty.
If if (countRes==2) evaluates to true, then what is the value of d.partie_id in that case?
Please provide these inputs.
Also, async.each does work at multiple levels. I did an implementation where I used async inside async. So, it doesn't look like the fault of async.
Related
I have a block of code that I will be using several times within a then statement in mocha so I turned it into a function. However I also need to call done()within that function and it's out of scope resulting in the error Uncaught ReferenceError: done is not defined. Here's a code snippet:
var collectionChecker = function(results) {
expect(Array.isArray(results), 'Did not return collection');
expect(results.length === numAttr, 'Returned wrong number of models');
done();
};
test('returns a collection with correct number of models', function(done) {
attrs.getAttributeTemplates().then(collectionChecker);
});
How can I pass done() to my function?
I found a workaround by chaining another .then and calling done there but it seems like an ugly way to do it.
You're overthinking it - mocha supports promises, you can return a promise and if it is fulfilled the test will pass (and if the expects throw it will fail):
var collectionChecker = function(results) {
expect(Array.isArray(results), 'Did not return collection');
expect(results.length === numAttr, 'Returned wrong number of models');
};
// just add a return, no `done` here or anywhere
test('returns a collection with correct number of models', function() {
return attrs.getAttributeTemplates().then(collectionChecker);
});
I want to make 2 api requests, but calling the second request inside the first's callback function doesn't seem right to me. Is there any way I can just call them both simultaneously and run the callback function only when I got respond from both?
You can use $.when() jquery function.
http://api.jquery.com/jquery.when/
You should use a variable outside the calls that increments on success. In the callback you test if it equals the number of calls, if true then you can call your finish method
Something like this:
var nbSuccess = 0;
var nbCalls = 2;
call_1.success
- nbSuccess++
- if nbSuccess == nbCalls {doFinish}
call_2.success
- nbSuccess++
- if nbSuccess == nbCalls {doFinish}
function doFinish...
Calling the second request inside the first one callback make them Synchronous. The second will only be called when the first has finished.
If you want two send the two call and handle only when the two are done you may (not tested)
Use the same callback for both and use a boolean to ensure both are done.
Something like (pseudo code):
var a1=false; a2=false;
a1.ajax(callback(){a1=true; doAction()}
a2.ajax(callback(){a2=true; doAction()}
function doAction() {
if (a1 && a2) {
...
}
You can do this
var response = 0;
var callback = function () {
if (response === 2){/* code */}
};
// first request
$.get(url).done(function () {
response++;
callback();
});
// second request
$.get(url).done(function () {
response++;
callback();
});
I hope this might helps you. Try this.
$.ajax("yourUrl",function(){
}).done(function(){
$.ajax("yourUrl",function(){
}).done(function(){
// Do your task
});
});
Suppose I use Node.js to try to run two async calls to get some answers. I know there's an async package, where you can just pass two functions, and an optional callback.
async.parallel([fun1(){callback(null,1);},
fun2(){callback(null,2);}],
function(err, results) {
});
But suppose I have a priority now, if fun1 returns a value, then I do not need fun2's answer, only if fun1 returns null, then I wait for fun2. So I don't want to use the callback function, because the callback waits for both functions to finish, and fun2 may take very long.
Right now I just use a very exhaustive way by creating a callback function for both async calls.
function(){
var theAnswer,FromFun1,FromFun2;
var reply1,reply2;
fun1(reply1="answered";FromFun1=1;complete());
fun2(reply2="answered";FromFun2=2;complete());
function complete(answer){
if(reply1=="answered"){
theAnswer=FromFun1;
}else if(reply1==null){
// Don't do anything because fun1 is not finished running.
}else if(reply2=="answered"){
theAnswer=FromFun2;
}else{
// Both have no answer, err.
}
}
}
Is there a better way to do this?
The trick I've used for this scenario is to return "done" in first argument of the callback:
async.parallel([
function(callback){
callback("done",1);
},
function(callback){
callback(null,2);
}
], function(err, results) {
console.log(err, results); // done [ 1 ] or done [ 1 , 2 ]
});
Sounds like a hack and I don't usually do it but in some rare cases like this one, it actually keeps the code clean... just document it so that others know what you intention is.
Its better to use waterfall instead of parallel execution coz you can pass the result form your previous function to next one as argument.
async.waterfall([
function(callback){
callback(null, 'one');
},
function(arg1, callback){
// arg1 now equals 'one'
if(arg1==null){
// it will not take time it returns immediately
callback(null, 'done');
}else{
// do your another stuff here fun2 logic here
// it will not be executed and so it dont take time
}
}
], function (err, result) {
// result now equals 'done'
});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I am in the process of relearning Javascript and last week when writing this code for a university assignment I think that there is probably a much better way of executing this code
app.get('/member/all', function(req, res) {
connection.query('CALL GetAllMembers()', function(err,rows){
connection.query('CALL CountMembers()', function(err, allMembers){
console.log(err);
connection.query('CALL CountAllIndMembers()', function(err,indMembers){
console.log(err);
connection.query('CALL CountInactiveMembers()', function(err,inactiveMembers){
console.log(err);
connection.query('CALL CountAllMembersInGroups()', function(err,groupMembers){
console.log(err);
res.render('members', {members : rows[0], title : "All Members", groupMembers : groupMembers[0][0].AllGrpMembers,
inactiveMembers : inactiveMembers[0][0].AllInactiveMembers, indMembers : indMembers[0][0].AllIndMembers,
allMembers : allMembers[0][0].AllMembers, statistics : true});
});
});
});
});
});
});
});
When I was trying to declare variables under the app.get such as var allMembers... when the callback was executed I was unable to set allMembers = rowsFromTheCallback. It seemed that it was a local variable to that callback. I'm sure this is something to do with the variable scope and/or hoisting. Just wanted to ask you guys if there would be a better way to do this as even though this function works. It is very ugly to look at haha!
Thanks in advance
Jack
As far as scope goes, all the inner functions should be able to read and write to the outer variable unless it is shadowed by an inner variable declaration or function parameter.
The problem you are having might be related to the async-ness of the code. See this code:
function delay(n, cb){
setTimeout(function(){ bs(delay) }, delay);
}
function main(){
var allMembers = 17;
delay(500, function(){
console.log(allMembers); // This looks at the outer "allMembers"
allMembers = 18;
delay(200, function(allMembers){ // <-- SHADOW
console.log(allMembers); // This looks at the allMembers from "delay 200"'s callback
allMembers = 42;
});
delay(300, function(){
console.log(allMembers); //This is the outside "allMembers" again
});
});
return allMembers; // Still 17!
}
main();
main will return before the setTimeouts have even fired so its going to return the original value of that variable. In order to wait for the inner callbacks to run, the only way is to make main take a callback to signa when its done, instead of just returning.
function main(onResult){
delay(500, function(){
//...
onResult(allMembers);
});
// <-- no return value
});
main(function(allM){
console.log(allM);
});
See async library: https://github.com/caolan/async
async.series([
getAllMembers,
countMembers,
...
], function(err, results) {
// err contains an error if any of the functions fails. No more functions will be run.
// results is an array containing results of each function if all the functions executed without errors
}));
function getAllMembers(callback) {
connection.query('CALL CountMembers()', callback);
}
function countMembers(callback) {
...
}
If the execution order of the functions does not matter, async.parallel can be used instead of async.series.
There is power in using a library to handle and encapsulate "Continuation Passing Style" (CPS) interactions with your asynchronous calls. The following code isn't from a library, but I'm going to walk through it and use it as an example of one way to implement CPS.
Setting up a scope appropriate queue is the first step. This example uses about the most simple method for doing so:
var nextList = [];
After that we need a method to handle our first case, the need to queue tasks to be performed in the future. In this case I was focused on performing them in order so I named it next.
function next() {
var todo,
current,
task,
args = {};
if (arguments.length > 0) { // if called with parameters process them
// if parameters aren't in an array wrap them
if (!Array.isArray(arguments['0'])) {
todo = [arguments];
} else { // we were passed an array
todo = [];
arguments['0'].forEach(function (item) {
// for each item we were passed add it to todo
todo.push(item);
});
}
nextList = todo.concat(nextList);
// append the new items to the end of our list
}
if (nextList.length > 0) { // if there are still things to do
current = Array.prototype.slice.apply(nextList.shift());
task = current[0];
args = current.slice(1);
task.apply(null, args); // execute the next item in the list
}
}
This allows us to make calls like:
.map(function (filepath) {
tasks.push(
[
handleAsset,
{
'path': filepath,
}
]
);
});
tasks.push([done]);
next(tasks);
This will call handleAsset, which is async, once for each file, in order. This will allows you to take your code and change each of the nested calls into a separate function in the form:
function memberAll() {
app.get('/member/all', function(req, res) {
if (err) {
handleError(err, 'memberAll');
} else {
next(getAllMembers, 'parameters to that call if needed');
}
});
}
where handleError is a common error handler, and the next call allows you to pass on relevant parameters to the next function that is needed. Importantly in the success side of the if statement you could either:
conditionally call one of several functions
call next with an array of calls to make, for instance if you had functions for processFolder and processFile you could expect that processing a folder might involve processing other folders and files and that the number would vary
do nothing except call next() with no parameters and end the current branch
Embellishments can include writing a clean function for emptying the nextList, adding items to nextList without calling an item from the list, etc. The alternative at this point is to either use an existing library for this or to continue writing your own.
I'm creating a Phonegap application that will perform differently on first run. The way that I am detecting the first run is by seeing of one of the database tables exists. As you can probably tell from the code below, I am checking for the error that is (probably) indicating that the table already exists, thus proving that this is not the application's first run.
function databaseExists(){
var exists;
database.transaction(function(tx){
tx.executeSql('CREATE TABLE GLOBAL (uid, property, value)');
}, function(err){
exists = true;
}, function(){
exists = false;
});
return exists;
}
My problem, however, is that the asynchronous execution of the Javascript code means that the function returns its value before the success (or error) function has set it's value.
This function is called in the initialising stage of the application:
if (databaseExists()){
// Do Something
}
And therefore must return the value rather than execute the function in the success callback of the transaction.
Is there a way to force the execution to wait until the database transaction is complete or return the value through the database.transaction object?
Thanks in advance,
Jon
You need to write it in callback form:
var dataBaseExists(yep, nope) {
database.transaction(function(tx) {
tx.executeSql('CREATE TABLE GLOBAL (uid, property, value)');
}, function(){
if (yep) {
yep.apply(this, arguments);
}
}, function(){
if (nope) {
nope.apply(this, arguments);
}
});
};
var itDoes = function() {
console.log("great");
};
var itDoesNot = function() {
console.log("what a pity");
};
databaseExists(itDoes, itDoesNot);
You need callbacks, but if don't need checking existment of your tables, you can do that easily with localStorage.
e.g.
if(localStorage.getItem('init') === null){
//init
localStorage.setItem('init', true);
}
You will avoid dealing with database.
and maybe this gonna be helpful "CREATE TABLE IF NOT EXISTS..."
I know there's gonna be programmers don't like my solution, but I love it!
var myfEspereti=false;
function Espereti(pStatus)
{
if (pStatus==="wait")
{
myfEspereti = true;
while(myfEspereti)
{
}
}
else if (pStatus==="go")
{
myfEspereti=false;
}
}
and then call Espereti ("wait") when you want to wait for an async call. Inside the async call, when it's finish, call Espereti ("go") and that's it!