2

I try to work with JS promises, using jQuery. I have a chain of promises like this:

function myPromisesChain(data)
{
    return $.when(data)
        .then(firstStep)
        .then(secondptStep)
        .then(thirdStep)
        // ...n Step
        .then(finalStep)
        .always(function(data){
            console.log('FINISHED: ' + JSON.stringify(data));
        });
}

That`s fine, but what to do, if I need to execute a step in a loop? Sad, but I cannot find a correct syntax so far... I expect something like this (approximately):

    function myPromisesChain(data)
{
    return $.when(data)
        .then(firstStep)
        .then(secondptStep)            
        .then(function(data){
            var counter = 0;
            var limit = 3;
            while(counter<limit){
                  thirdStep(data.transaction[counter]);
                  counter++;
            }
            return data;
        })
        // ...n Step
        .then(finalStep)
        .always(function(data){
            console.log('FINISHED: ' + JSON.stringify(data));
        });
}

Problem is that function in a loop is a promise itself.

  • Check this out: https://stackoverflow.com/a/6558326/529544 – JDandChips Feb 14 '19 at 11:42
  • you might want to have a look on `async/await` – Muhammad Usman Feb 14 '19 at 11:44
  • Your question needs to clarify another point here, you want to execute thirdStep in loop. But you want to execute in series or parallel? If you want to execute in series, my solution will work, if you want to execute them in parallel you need to go with the solution provided by @effective-robot – AvcS Feb 14 '19 at 12:02

2 Answers2

0

Every then method returns a new Promise, calling then on another then implies, you are calling the second then on the Promise returned by previous then.

So you can just save the reference of Promise returned by previous then and use it bind new then to it.

The IIFE inside the loop is needed to save the reference to counter value at the time of execution

function myPromisesChain(data) {
    var promise = $.when(data)
        .then(firstStep)
        .then(secondptStep);

    var counter = 0;
    var limit = 3;
    while (counter < limit) {
        promise = (function (counter) {
            return promise.then(function(data) {
                return thirdStep(data.transaction[counter]);
            });
        })(counter++);
    }

    return promise
        // ...n Step
        .then(finalStep)
        .always(function (data) {
            console.log('FINISHED: ' + JSON.stringify(data));
        });
}
AvcS
  • 2,263
  • 11
  • 18
  • You're overwriting `promise` each time through the loop. At the end you'll just wait for the last one, not any of the others. – Barmar Feb 14 '19 at 11:44
  • Also, you have the [infamous loop issue](https://stackoverflow.com/questions/1451009/javascript-infamous-loop-issue) with the `counter` variable. – Barmar Feb 14 '19 at 11:45
  • Never mind my first comment, I now see that you're chaining the `promise` variable to the previous one. But you still have the problem with the `counter` variable in the callback function. It will be equal to `limit` when the callbacks occur. – Barmar Feb 14 '19 at 11:47
  • @Barmar when you chain multiple thens, each then waits for the prev then to resolve, and the promise you get as return value of the chain is always the promise returned by last then – AvcS Feb 14 '19 at 11:49
  • Got it, i just copied the code he gave, didn't thought about the loop :D, updated the code – AvcS Feb 14 '19 at 11:49
0

Your function in .then should return a Promise. Assuming that thirdStep does return a Promise, you can add its return values to an array as you go, and then use Promise.all to ensure they're all resolved.

.then(function(data) {
    var counter = 0;
    var limit = 3;
    var returns = [];
    while(counter<limit){
        returns.push(thirdStep(data.transaction[counter]));
        counter++;
    }
    return Promise.all(returns);
})
Effective Robot
  • 366
  • 1
  • 6
  • This variant looks ok, but there is one problem: experssion returns.push(thirdStep(data)) uses the last value of data object in all the calls, but i need to use this argument vith its own value in each iteration. Can I solve this? – Олег Сидоров Feb 14 '19 at 13:40
  • @ОлегСидоров You're calling `thirdStep` from within the function that `data` is a parameter of, and you're not changing `data` anywhere within it. I'm not sure what you're trying to get at. – Effective Robot Feb 14 '19 at 17:08
  • My example is very simplified. Indeed, I need to call thirdStep several times, each time with new values in argument. – Олег Сидоров Feb 15 '19 at 06:23