Исправить для реализации цикла

Я написал некоторый код для преобразования документации Swagger 1 в Swagger 2. Я указываю метод преобразования для нескольких ресурсов в массиве. я обнаружил, что он не выполняется правильно и видит, как он прыгает в отладчике до конца моего массива (размер 34). Как я могу убедиться, что он проходит через мой код правильно?

for(var i = 0; i < resourcesArray.length; i++) {
    Converter.convert({
        from: 'swagger_1',
        to: 'swagger_2',
        source: 'http://example/' + resourcesArray[i]
    }, function (err, converted) {
        console.log(resourcesArray[i]);
        // [Optional] Fill missing fields with dummy values
        converted.fillMissing();

        // [Optional] Validate converted spec
        var fileName = resourcesArray[i] + '.json';
        fs.writeFileSync(fileName, converted.stringify());
    })
}

3 ответа

Решение

Вы стали жертвой ограниченных правил JavaScript. Попробуй это:

resourcesArray.forEach(function (resource) {
    Converter.convert({
        from: 'swagger_1',
        to: 'swagger_2',
        source: 'http://example/' + resource
    }, function (err, converted) {
        console.log(resource);
        // [Optional] Fill missing fields with dummy values
        converted.fillMissing();

        // [Optional] Validate converted spec
        var fileName = resource + '.json';
        fs.writeFileSync(fileName, converted.stringify());
    });
});

Проблема заключалась в том, что к тому времени асинхронный обратный вызов function (err, converted) { ... } происходит, i равно resourcesArray.length потому что итерация уже завершена. Вот как JavaScript var объявленные переменные работают. Используя forEach цикл гарантирует, что область всегда содержит resource вы ожидаете для этой операции.

Кроме того, если ES6 в порядке, то вы можете изменить var в let и это также решило бы проблему, потому что let-объявленные переменные используют лексическую область видимости, что означает, что блок цикла for всегда будет содержать ожидаемое значение i даже если он используется внутри асинхронного обратного вызова.

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

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

for(var i = 0; i < resourcesArray.length; i++) {
  (function(i) {
    // Do work here with the value i
  })(i);
}

Это может произойти, потому что внутри вашего асинхронного вызова for петля. Вам нужно заморозить значение iдля каждой итерации. Ты можешь использовать closure() за это. Если вы хотите отслеживать, когда все итерации завершены, вы можете сохранить счетчик: var counter = resourcesArray.length; for(var i = 0; i

  (function( resources, i ){
     Converter.convert({
        from: 'swagger_1',
        to: 'swagger_2',
        source: 'http://example/' + resources
    }, function (err, converted) {
        console.log(resources);
        // [Optional] Fill missing fields with dummy values
        converted.fillMissing();

        // [Optional] Validate converted spec
        var fileName = resources + '.json';
        fs.writeFileSync(fileName, converted.stringify());

        counter--;
        if( counter <= 0 )
        {
          //next();
        }
    })
  })(resources, i );    
}//for
Другие вопросы по тегам