sequential call using promise inside loop

It looks to me like this is caused by executing a series of asynchronous inserts, and assuming that the get of insert n (inside of a .then()) is called before insert n+1 is executed. However, I'm not aware of any such guarantee, in JavaScript; all that I'm familiar with is that then n will be called after insert n, not that it would be called before insert n+1.

What I'd suggest is avoiding this mix of traditional and callback-based code, and instead put the iteration step inside getFeedbackTrack().then. Assuming this understanding of the issue is correct, then something like the following should work:

function iterate(i) {
    if (i < data.length) {
        obj.insertFeedbackTrack(data[i]).then(function(insertResult) {
            self.getFeedbackTrack().then(function(getResult) {
                // this line is the important one, replacing the `for` loop earlier
                iterate(i+1);
            });
        });
    }
}

iterate(0);

By doing that, you would guarantee that insert for the next element does not occur until the current select executes successfully.

Naturally, you may also want to restructure that to use chained .then instead of nested; I used nested rather than chained to emphasize the ordering of callbacks.


The previous answer is good, but if you are using nodejs, or babel, or you are using only modern browsers. You can use an async-await pair, it is es8 stuff.

let insertFeedbackTrack = function(){ return new Promise(/***/)};
let getFeedbackTrack = function(){ return new Promise(/***/)};
let processResult = async function(data){
   let feedbacks = [];
   for(let i=0;i<data.length;i++){
      let insertedResult = await insertFeedbackTrack(data[i]);//perhaps you will return an id;
      let feedbackTrack = await getFeedbackTrack(insertedResult.id);
      feedbacks.push(feedbackTrack);
   }
   return feedbacks;
} 

processResult(data).then(/** do stuff */)

This can be solved by using a very handy JS library Ramda. Concept is to use two methods, one is R.partial and another is R.pipeP.

First create a promises array from your data array, like following.

var promises = data.map(function(i) {
  return R.partial(sample, [i])
});

Then you can pass this promise to R.pipeP, so that it can be executed one after another. like below.

var doOperation = R.pipeP.apply(this, promises)

Please execute following snippet attached.

// Sample promise returning function
function sample(d) {
  return new Promise(function(resolve, reject){
    setTimeout(function() {
      console.log('resolved for:' + d);
      resolve(d);
    }, 1000)
  })
}

// Sample data
var data = [1, 2, 3, 4, 5]

// Converting data array to promise array
var promises = data.map(function(i) {
  return R.partial(sample, [i])
});

var doOperation = R.pipeP.apply(this, promises)
doOperation();
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

So in your case, the code will look like this

var promises = data.map(function(i) {
  return R.partial(self.executeFeedbackTrack, [i])
});
var doOperation = R.pipeP.apply(this, promises)
doOperation();

Tags:

Javascript