Я обнаружил, что IE10 и IE Edge делают вещи немного по-разному. пойди разберись с

Я бегу цикл обработки событий следующей формы:

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

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

jQuery действительно классный, но не позволяйте чистому JavaScript упасть в забвение … i. Любые рекомендации о том, как это исправить?

политики одного и того же происхождения как дубликат Цербр Javascript Пользователи с Javascript Этот параметр требует вопросы как дубликаты и повторно открывайте их по мере необходимости. 23 августа ’18 в 10:20

Этот вопрос уже задавался ранее и уже имеет ответ. Если эти ответы не полностью отвечают на ваш вопрос, пожалуйста, задайте новый вопрос Глядя на вывод

Переменная for запускается сразу до завершения, пока все ваши асинхронные операции запущены. Когда они завершат какое-то время в будущем и вызовут свои обратные вызовы, значение вашей индексной переменной цикла i Я думаю, что у меня есть более элегантный способ делегирования событий, и захват событий на

Это потому, что применяется метод for не ожидает завершения асинхронной операции, прежде чем перейти к следующей итерации цикла и потому что асинхронные обратные вызовы вызываются некоторое время в будущем. Таким образом, цикл завершает свои итерации, и затем обратные вызовы вызываются, когда эти асинхронные операции завершаются. Таким образом, индекс цикла «готов» и находится в своем окончательном значении для всех обратных вызовов.

Чтобы обойти это, вы должны уникальным образом сохранять индекс цикла отдельно для каждого обратного вызова. В Javascript способ сделать это — захватить его в закрытии функции. Это может быть сделано либо созданием встроенной функции закрытия специально для этой цели (первый пример показан ниже), либо вы можете создать внешнюю функцию, которой вы передадите индекс, и позволить ему поддерживать индекс уникально для вас (второй пример показан ниже).

Начиная с 2016 года, если у вас есть полная реализация Javascript для ES6, вы также можете использовать let для определения for, и она будет уникально определяться для каждой итерации цикла for (третья реализация приведена ниже). Но обратите внимание, что это поздняя реализация в реализациях ES6, поэтому вы должны убедиться, что ваша среда выполнения поддерживает эту опцию.

Используйте .forEach () для итерации, поскольку она создает свое собственное закрытие функции

someArray.forEach(function(item, i) {
    asynchronousProcess(function(item) {
        console.log(i);
    });
});

Создайте свое собственное закрытие функции с помощью IIFE

var j = 10;
for (var i = 0; i < j; i  ) {
    (function(cntr) {
        // here the value of i was passed into as the argument cntr
        // and will be captured in this function closure so each
        // iteration of the loop can have it's own value
        asynchronousProcess(function() {
            console.log(cntr);
        });
    })(i);
}

Создайте или измените внешнюю функцию и передайте ей переменную

Если вы можете изменить asynchronousProcess(), тогда вы могли бы просто передать значение туда и получить функцию asynchronousProcess() cntr для обратного вызова следующим образом: строгий режим

var j = 10;
for (var i = 0; i < j; i  ) {
    asynchronousProcess(i, function(cntr) {
        console.log(cntr);
    });
}

: Я всегда хотел сделать версию кода с минимальным / повышенным разрешением, поэтому вот код обещания ES6: let

, который отлично работает при любых обстоятельствах. let в вашем for объявляется в

const j = 10;
for (let i = 0; i < j; i  ) {
    asynchronousProcess(function() {
        console.log(i);
    });
}

let для каждого вызова цикла (это то, что вы хотите). for FWIW, есть еще один способ, которым вы могли бы пойти с этим … Подключите ваши обработчики событий, используя jQuery, и используйте i, поэтому его не нужно добавлять, если вы используете ES6.

Посмотрите на эти утверждения и примеры из MDN:

Если ваша асинхронная функция возвращает обещание, и вы хотите сериализовать ваши асинхронные операции для запуска одна за другой вместо параллельного, и вы работаете в современной среде, которая поддерживает async и await Это гарантирует, что только один вызов

async function someFunction() {
    const j = 10;
    for (let i = 0; i < j; i  ) {
        // wait for the promise to resolve before advancing the for loop
        await asynchronousProcess();
        console.log(i);
    }
}

строгого режима для функций: аналогично, чтобы вызвать строгий режим для функции, поместите точное выражение «использовать строгий» ; (или «используйте строгий» { ***}) в теле функции перед любыми другими утверждениями. asynchronousProcess() во время полета, а for даже не продвинется до тех пор, пока не завершится каждая. Это отличается от предыдущих схем, в которых все асинхронные операции выполнялись параллельно, поэтому полностью зависит от того, какой дизайн вы хотите. Примечание: функция await, работает с обещанием, поэтому ваша функция должна возвращать обещание, которое разрешено / отклонено после завершения асинхронной операции. Также обратите внимание, что для использования await подробнее на MDN async Глядя на вывод

Любая рекомендация о том, как это исправить?

Некоторые люди, которые были в комитете ECMAScript, хорошо поговорили: bind :

for (i = 0; i < j; i  ) {
    asycronouseProcess(function (i) {
        alert(i);
    }.bind(null, i));
}

Или, если ваш браузер поддерживает переключатель let (это будет в следующей версии ECMAScript, однако Firefox уже поддерживает его, так как while) у вас может быть:

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 Как отслеживать поддержку браузера curry Помните, это работает, только если

async await здесь (ES7), так что теперь вы можете делать такие вещи очень легко.

  var i;
  var j = 10;
  for (i = 0; i < j; i  ) {
    await asycronouseProcess();
    alert(i);
  }

возвращает asycronouseProcess все части Promise

Вот мое решение. Как сказал Энди Э., отвечая на вопрос asycronouseProcess не находится под вашим контролем, тогда вы можете сделать так, чтобы он возвращал Promise самостоятельно, как это

function asyncProcess() {
  return new Promise((resolve, reject) => {
    asycronouseProcess(()=>{
      resolve();
    })
  })
}

Затем замените эту строку await asycronouseProcess();. Понимание await asyncProcess();

Код функции — это код строгого режима, если связанные Promises по сравнению с ожидаемым async await должен Вот пример функционального подхода к тому, что ожидается здесь. async await С чем вы столкнулись

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

для вашего асинхронного процесса — хороший вариант.

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

Затем вызовите функцию (XHRPost) внутри цикла for, но с волшебным ключевым словом Await. :)

Основные причины, по которым разработчики должны использовать

let http = new XMLHttpRequest();
let url = 'http://sumersin/forum.social.json';

function XHRpost(i) {
  return new Promise(function(resolve) {
    let params = 'id=nobot&:operation=social:createForumPost&subject=Demo'   i   '&message=Here is the Demo&_charset_=UTF-8';
    http.open('POST', url, true);
    http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    http.onreadystatechange = function() {
    console.log("Done "   i   "<<<<>>>>>"   http.readyState);
          if(http.readyState == 4){
              console.log('SUCCESS :',i);
              resolve();
          }
         }
    http.send(params);       
    });
 }
 
(async () => {
    for (let i = 1; i < 5; i  ) {
        await XHRpost(i);
       }
})();