Подписка на наблюдаемые в циклическом [dубликате]

Я запускаю цикл событий следующего вида:

var i;
var j = 10;
for (i = 0; i < j; i++) {

    asynchronousProcess(callbackFunction() {
        alert(i);
    });
}

Я пытаюсь отобразить серию предупреждений, показывающих числа от 0 до 10. Проблема в том, что к моменту, когда функция обратного вызова , цикл уже прошел через несколько итераций, и он отображает более высокое значение i. Любые рекомендации о том, как это исправить?

71
задан 13 March 2018 в 04:47

4 ответа

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

Вот пример функционального подхода к ожидаемому здесь.

1
ответ дан 15 August 2018 в 15:50

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

Решение зависит от того, что вам действительно нужно , Если пример близок к тому, что вам нужно, предложение @ Simon передать i вашему асинхронному процессу является хорошим.

0
ответ дан 15 August 2018 в 15:50

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)

7
ответ дан 15 August 2018 в 15:50
Любая рекомендация о том, как это исправить?

Несколько. Вы можете использовать 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 (которая не нуждается в объекте контекста).

10
ответ дан 15 August 2018 в 15:50
  • 1
    Пример ECMAScript является очень хорошим, чтобы продемонстрировать, что может сделать let. – hazelnut 14 January 2016 в 08:00
  • 2
    Есть ли asyncronouseProcess во всех ответах какой-то заполнитель? Я получаю & quot; не определен & quot ;. – JackHasaKeyboard 20 November 2017 в 03:47
  • 3
    [F1] является частью исходного вопроса, так что да, это нормально, если оно дает вам «не определено». Вы можете просто заменить его любой асинхронной функцией, если вы хотите проверить исходную проблему и как работает предлагаемое решение. Например: function asycronouseProcess(fn){ setTimeout(fn, 100);} – ZER0 22 November 2017 в 01:18

Другие вопросы по тегам:

Похожие вопросы: