【问题标题】:Correct for loop implementation正确的for循环实现
【发布时间】:2016-11-22 14:06:52
【问题描述】:

我编写了一些代码来将 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());
    })
}

【问题讨论】:

  • 那是...... for 循环的作用......它遍历整个数组执行里面的内容。回调会在一段时间后发生,并且不能保证其顺序正确。

标签: javascript node.js callback order-of-execution


【解决方案1】:

您已成为 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 的预期值,即使它在异步回调中使用。

【讨论】:

    【解决方案2】:

    您的循环正确,但问题是 JavaScript 没有为 for 主体创建闭包。由于您在循环中启动了一个异步操作,所以在异步操作完成并调用您的回调时,i 的值已经发生了变化。

    所以你必须立即在 for 循环中创建一个闭包,在闭包中存储你想要的值,然后在闭包中定义回调的同时调用异步操作。

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

    【讨论】:

    • 附带说明,如果 ES6 可以接受,for (let i = 0; i &lt; resourcesArray.length; i++) { /* Do work here with the value i */ } 也可以。
    【解决方案3】:

    这可能是因为您的 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
    

    【讨论】:

      猜你喜欢
      • 2021-12-02
      • 2021-10-28
      • 1970-01-01
      • 2020-02-08
      • 2021-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多