简体   繁体   中英

How to synchronise then() inside for loop

I am facing problem while calling a then() function inside for loop here is my below code

The chunk of code

StretchData.getById(item).then(function (data) 

Is calling after j==3 but my requirement it should call each iteration Any idea how to achieve this.I tried many things still no result.

for (var j = 0; j < 3; j++) {

                StretchData.getById(item)
                .then(function (data) {
                    alert(startWorkOutModel.sortValue);
                    startWorkOutModel.inStretchedData = {
                        sort: startWorkOutModel.sortValue,
                        sData: data.result
                    }
                    startWorkOutModel.stretchedData.push(startWorkOutModel.inStretchedData);
                    fl = true;
                    console.log(JSON.stringify(startWorkOutModel.stretchedData));
                    // break;

                },
                function (error) {
                    alert(JSON.stringify(error));
                });                            

      }

When you have a loop or array that you need to process asynchronously in parallel, you build up an array of the promises returned by then and then wait for them all using Promise.all . You'd also normally handle errors on the promise from Promise.all rather than individually, unless you're able to do error-correction and return something to use instead of the error.

Something along these lines:

var promises = [];
for (var j = 0; j < 3; j++) {
    promises.push(
        StretchData.getById(item)
            .then(function(data) {
                // *** Gets called for each individual item
                alert(startWorkOutModel.sortValue);
                startWorkOutModel.inStretchedData = {
                    sort: startWorkOutModel.sortValue,
                    sData: data.result
                }
                startWorkOutModel.stretchedData.push(startWorkOutModel.inStretchedData);
                fl = true;
                console.log(JSON.stringify(startWorkOutModel.stretchedData));

                // *** Normally you'd want to return something here
            })
    );
}
Promise.all(promises)
    .then(
        function(results) {
            // *** Use results (an array of the promise results) here
        },
        function(error) {
            // *** At least one promise failed
        }
    );

As I mentioned in a comment on the question, you're not using j within the loop, so that does the same exact thing three times in a row. If you needed to use j in the promise callback code, you have two options:

ES5 and earlier

Use a function to capture the value of j into an unchanging variable the callback can use (since j will be 3 by the time any of those callbacks runs):

function doRequestFor(value) {
    return StretchData.getById(item)
            .then(function(data) {
                // *** Gets called for each individual item
                // *** Use `value` here (in place of `j`)
                alert(startWorkOutModel.sortValue);
                startWorkOutModel.inStretchedData = {
                    sort: startWorkOutModel.sortValue,
                    sData: data.result
                }
                startWorkOutModel.stretchedData.push(startWorkOutModel.inStretchedData);
                fl = true;
                console.log(JSON.stringify(startWorkOutModel.stretchedData));

                // *** Normally you'd want to return something here
            });
}
var promises = [];
for (var j = 0; j < 3; j++) {
    promises.push(getRequestFor(j));
}
Promise.all(promises)
    .then(
        function(results) {
            // *** Use results here
        },
        function(error) {
            // *** At least one promise failed
        }
    );

ES2015 (aka "ES6") and later

You can make use of let 's handling in for loops which means each loop iteration gets its own copy of j :

let promises = [];
for (let j = 0; j < 3; j++) {
//   ^^^---------------------------- *** Note
    promises.push(
        StretchData.getById(item)
            .then(function(data) {
                // *** Gets called for each individual item
                // *** Use `j` here, it'll be 0, 1, or 2
                alert(startWorkOutModel.sortValue);
                startWorkOutModel.inStretchedData = {
                    sort: startWorkOutModel.sortValue,
                    sData: data.result
                }
                startWorkOutModel.stretchedData.push(startWorkOutModel.inStretchedData);
                fl = true;
                console.log(JSON.stringify(startWorkOutModel.stretchedData));

                // *** Normally you'd want to return something here
            })
    );
}
Promise.all(promises)
    .then(
        function(results) {
            // *** Use results (an array of the promise results) here
        },
        function(error) {
            // *** At least one promise failed
        }
    );

First of all. Variables declared with var in JavaScript are function-scoped and not block scoped which means (because the callback is asynchronous) that j will be 3 in all callback executions. You can get around that fact by declaring the variable j with let which instead block scopes it.

for (let j = 0; ...

Second. Is it important that the callbacks are run in series? In that case you will have to refactor your code considerably. Maybe making the call recursive and chain the next call of the loop to the callback of the first.

If not, but it is still important that you can act when all callbacks are completed, you can store the deferreds in a list and pass them to Promise.all(yourDeferredList) which will callback when all are completed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM