Я запускаю цикл событий следующего вида:
var i;
var j = 10;
for (i = 0; i < j; i++) {
asynchronousProcess(callbackFunction() {
alert(i);
});
}
Я пытаюсь отобразить серию предупреждений, показывающих числа от 0 до 10. Проблема в том, что к моменту, когда функция обратного вызова , цикл уже прошел через несколько итераций, и он отображает более высокое значение i. Любые рекомендации о том, как это исправить?
var i = 0;
var length = 10;
function for1() {
console.log(i);
for2();
}
function for2() {
if (i == length) {
return false;
}
setTimeout(function() {
i++;
for1();
}, 500);
}
for1();
Вот пример функционального подхода к ожидаемому здесь.
JavaScript-код работает в одном потоке, поэтому вы не можете блокировать до конца завершения первой итерации цикла до начала следующего, не оказывая серьезного влияния на удобство использования страницы.
Решение зависит от того, что вам действительно нужно , Если пример близок к тому, что вам нужно, предложение @ Simon передать i вашему асинхронному процессу является хорошим.
async await здесь (ES7), поэтому вы можете сделать это сейчас очень легко.
var i;
var j = 10;
for (i = 0; i < j; i++) {
await asycronouseProcess();
alert(i);
}
Помните, что это работает, только если asycronouseProcess возвращает Promise [ ! d1]
Если asycronouseProcess не находится под вашим контролем, вы можете заставить его возвратить Promise самостоятельно, как это
function asyncProcess() {
return new Promise((resolve, reject) => {
asycronouseProcess(()=>{
resolve();
})
})
}
Затем замените эту строку await asycronouseProcess(); на await asyncProcess();
Помните, что это работает, только если asycronouseProcess возвращает Promise (Также читаем о поддержке для async await)
Несколько. Вы можете использовать bind:
for (i = 0; i < j; i++) {
asycronouseProcess(function (i) {
alert(i);
}.bind(null, i));
}
Или, если ваш браузер поддерживает bind (он будет в следующей версии ECMAScript, однако Firefox уже поддерживает его с некоторого времени), вы можете have:
for (i = 0; i < j; i++) {
let k = i;
asycronouseProcess(function() {
alert(k);
});
}
Или вы могли бы выполнить работу bind вручную (в случае, если браузер не поддерживает его, но я бы сказал, что вы можете реализовать прокладку в этом случае, это должно в ссылке выше):
for (i = 0; i < j; i++) {
asycronouseProcess(function(i) {
return function () {
alert(i)
}
}(i));
}
Обычно я предпочитаю let, когда могу его использовать (например, для дополнения Firefox); в противном случае bind или пользовательская функция currying (которая не нуждается в объекте контекста).