#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)
который будет выполнен обратный вызов, когда все будут завершены.