1

I am working with a transnational framework within Javascript. So I need to wait for the previous query to finish before I move on. For example...

// Explicit this won't work because the length is not static
var i = [1,2,3]
doSomething(i[0], function(){
  doSomething(i[1], function(){
    doSomething(i[2], function(){
       commitTransaction()
    }
  })
})

From this example I can't figure out a way to do this dynamically. It feels like a queue/recursion problem but I can't seem to crack it.

Does anyone else have an idea? I can also wrap in promises so that is an option as well, although that seems less synchronous.

2
  • Does doSomething have any ajax or timeouts? Commented Sep 23, 2015 at 21:24
  • Not sure I understand the question well enough to give an official answer, but if the main problem with your example is that you don't know the length ahead of time, then what you probably want is a recursive function Commented Sep 23, 2015 at 21:29

3 Answers 3

1

Use async.eachSeries. So your code would translate to:

var transaction = {...};
async.eachSeries([1, 2, 3], function(value, callback) {
  doSomething(value, transaction, callback);
}, function(err) {
  if(err) throw err; // if there is any error in doSomething
  commitTransaction(transaction);
});
Sign up to request clarification or add additional context in comments.

7 Comments

async.each does the operations in parallel. If you need serially, use async.eachSeries github.com/caolan/async#synchronous-iteration-functions
@ChrisPerkins My bad. Thanks for pointing out. Updated the answer.
Is there a way to do this exact thing only pass a variable to the commit transaction for example I want to pass transaction in this code... async.eachSeries(regulation.sources, function(source, callback){ mergeSource(source, transaction, callback); }, commitTransaction); // transaction needs passed to commitTransaction
@Jackie How do you get the transaction variable. From mergeSource function or do you have it before the loop begins?
@Jackie Updated the answer. Let me know if this solves your need.
|
1

jsFiddle Demo

I would suggest making a queue to do this. It would take the array, the generic callback function and a final function to callback with. Basically, the best way to accomplish this is to allow your functions to expect to have values injected.

The core assumption is that it is understood the caller will allow their callback function to have the current value and next callback function injected. That basically means we will end up with a function I have named queueAll which looks like this

function queueAll(arr,cbIteration,final){
 var queue = [function(){ cbIteration(arr[arr.length-1],final) }];
 for(var i = arr.length-2; i > 0; i--){
  (function(next,i){
   queue.unshift(function(){ cbIteration(arr[i],next) });
  })(queue[0],i)
 }
 cbIteration(arr[0],queue[0]);   
}

It takes the final call, places it in the queue, and then iterates, placing subsequent callback functions in the queue with the current value closed over, as well as closing over the front of the queue which at that point is the next call back. It is fairly simple to use. Pass it an array, a callback which expects values to be injected, and a final function.

In your case it would look like

queueAll(i,function(item,next){
 doSomething(item,next);
},function(){
 commitTransaction(); 
});

Stack Snippet Demo

//## <helper queue>

function queueAll(arr,cbIteration,final){
 var queue = [function(){ cbIteration(arr[arr.length-1],final) }];
 for(var i = arr.length-2; i > 0; i--){
  (function(next,i){
   queue.unshift(function(){ cbIteration(arr[i],next) });
  })(queue[0],i)
 }
 cbIteration(arr[0],queue[0]);   
}

//## </helper queue>

//## <user defined functions>

function doSomething(val,callback){
 setTimeout(function(){
     console.log(val);
     callback();
 },val*10);
}

function commitTransaction(){
 console.log("commit");   
}

//## </user defined functions>

//## <actual use>

var arr = [10,20,30];

queueAll(arr,function(item,next){
 doSomething(item,next);
},function(){
 commitTransaction(); 
});

//## </actual use>

1 Comment

I like this approach as well, I just used the async approach since it was simpler for me. But I like this as a more native approach!
0

Actually, I think promises are exactly what you're looking for. But for a traditional callback approach, consider the following:

var state = false,

doSomething = function (value, callback) {
    /* do stuff with value */
    if (!state)
        doSomething(newValue, callback);
    else
        callback();
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.