Как синхронизировать then() внутри цикла for

#javascript

#javascript

Вопрос:

Я сталкиваюсь с проблемой при вызове then() функции внутри цикла for вот мой приведенный ниже код

Фрагмент кода

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

Вызывается после j== 3, но мое требование, чтобы оно вызывало каждую итерацию, любая идея, как этого добиться.Я перепробовал много вещей, но безрезультатно.

 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));
                });                            

      }
 

Комментарии:

1. Похоже, вы никогда не используете j внутри цикла. Это действительно правильно? Вы хотите сделать то же самое три раза?

2. недостаточно описания. укажите проблему в описании.

3. И в чем именно проблема?

4. Если вам нужно, чтобы значение ‘j’ было равно 1 для первого, то это разрешает и т.д., Используйте замыкание, чтобы «сохранить»значение. Но было бы полезно знать, что именно должен делать ‘j’. И это собственные обещания ES6 или вы используете библиотеку, может быть, вы можете что-то сделать с promise.all().progress() .

Ответ №1:

Когда у вас есть цикл или массив, который вам нужно обрабатывать асинхронно параллельно, вы создаете массив возвращаемых обещаний then , а затем ждете их использования Promise.all . Вы также обычно обрабатываете ошибки по обещанию, Promise.all а не по отдельности, если только вы не можете выполнить исправление ошибок и вернуть что-то для использования вместо ошибки.

Что-то в этом роде:

 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
        }
    );
 

Как я упоминал в комментарии к вопросу, вы не используете j внутри цикла, так что это делает одно и то же три раза подряд. Если вам нужно было использовать j в коде обратного вызова promise, у вас есть два варианта:

ES5 и более ранние версии

Используйте функцию для преобразования значения j в неизменяемую переменную, которую может использовать обратный вызов (поскольку j это будет 3 к моменту выполнения любого из этих обратных вызовов):

 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 (он же «ES6») и более поздние версии

Вы можете использовать let обработку в for циклах, что означает, что каждая итерация цикла получает свою собственную копию 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
        }
    );
 

Ответ №2:

Прежде всего. Переменные, объявленные с var помощью в JavaScript, имеют функциональную область, а не область блока, что означает (поскольку обратный вызов асинхронный), что j будет равно 3 во всех выполнениях обратного вызова. Вы можете обойти этот факт, объявив переменную j , с let помощью которой вместо этого блокирует ее.

 for (let j = 0; ...
 

Второй. Важно ли, чтобы обратные вызовы выполнялись последовательно? В этом случае вам придется значительно реорганизовать свой код. Возможно, сделать вызов рекурсивным и связать следующий вызов цикла с обратным вызовом первого.

Если нет, но по-прежнему важно, чтобы вы могли действовать, когда все обратные вызовы будут завершены, вы можете сохранить отсрочки в списке и передать их, в Promise.all(yourDeferredList) который будет выполнен обратный вызов, когда все будут завершены.