【问题标题】:For-loop incrementing to limit before being passed to function在传递给函数之前,for循环递增到限制
【发布时间】:2015-10-13 00:42:34
【问题描述】:

我有一些代码可以为dirs 数组中的每个源目录和目标目录复制包含在数组中的文件。通过循环的每次迭代,它都会调用复制的函数。它看起来像这样:

var filesInEachDir ["file1", "file2", "file3"];
var dirs = [
  {"source": "sourceDirectory1", "dest":"destinationDirectory1"},
  {"source": "sourceDirectory2", "dest":"destinationDirectory2"},
  {"source": "sourceDirectory3" "dest":"destinationDirectory3"},
];

for (var i = 0; i < dirs.length; i++){
  fs.mkdir(dirs[i], function(err){
    if(err){
      console.log(err);
    }else{
      copyFiles(dirs[i], filesInEachDir);
    }
   });
}

function copyFiles(dirs, files){
  for (var c = 0; c < files.length; c++){
    fs.copy(files[c], dirs.source, dirs.dest, {replace: false}, function(err){
      if (err){
        console.log(err);
      }else{
        console.log('file copied');
      }
    });
  }
}

由于某种原因,只复制了dirs 的最后一个元素中的文件。如果我向dirs 添加另一个元素,它的文件将被复制,而不是其他任何文件。所以看起来i 在调用copyFiles 函数之前完全递增。为什么会这样?我怎样才能给copyFiles i 的每个递增值?

【问题讨论】:

  • 什么是fs.mkdir?它传递的函数参数是异步调用的吗?这会导致这个问题。
  • @IMTheNachoMan 是的,mkdir 是异步的。
  • @Paulpro 您标记为重复的帖子中建议的forEach 方法并没有解决我的问题。我不认为这是同一个问题。我认为它必须与mkdir 的异步性质有关。你确定这是同一件事吗?
  • 是同一个东西,通常的原因是异步回调。一个 forEach 循环应该修复它:dirs.forEach( function ( dir ) { fs.mkdir( dir, function ( ) { ... else{ copyFiles( dir, filesInEachDir ); } }); });
  • @thomas 我重新打开了它,但我建议重新阅读您的问题并确保您发布的内容在语法上正确并完全重现了您的错误。您对fs.mkdir 的呼叫似乎没有关闭,没有})

标签: javascript node.js for-loop closures fs


【解决方案1】:

您遇到了在异步函数上使用for 循环引起的经典问题:循环在它调用的任何函数执行之前很久就完成了,因此当第一个函数实际开始执行某些操作时,它引用的循环索引to 已被覆盖。

请改用.forEach 以避免覆盖循环索引。

var filesInEachDir = ["file1", "file2", "file3"];
var dirs = [
  {"source": "sourceDirectory1", "dest":"destinationDirectory1"},
  {"source": "sourceDirectory2", "dest":"destinationDirectory2"},
  {"source": "sourceDirectory3", "dest":"destinationDirectory3"}
];

dirs.forEach(function (dir) {
  fs.mkdir(dir, function(err) {
    if (err) {
      console.log(err);
    } else {
      copyFiles(dir, filesInEachDir);
    }
  });
});

function copyFiles(dir, files) {
  files.forEach(function (file) {
    fs.copy(file, dir.source, dir.dest, {replace: false}, function(err) {
      if (err) {
        console.log(err);
      } else {
        console.log('file copied');
      }
    });
  });
}

归结为正确地确定变量的范围。在您的代码中,i 在您的 mkdir 回调中查看时处于更高的范围内。 i 的内容由for 循环在外部控制。您需要一个 local 数组索引。

您可以使用IIFE 关闭i 并创建一个拥有自己副本的回调:

for (var i = 0; i < dirs.length; i++){
  fs.mkdir(dir, (function (i) {
    return function(err) {
      if (err) {
        console.log(err);
      } else {
        copyFiles(dirs[i], filesInEachDir);
      }
    };
  })(i));
}

或者更好

for (var i = 0; i < dirs.length; i++){
  fs.mkdir(dir, (function (dir) {
    return function(err) {
      if (err) {
        console.log(err);
      } else {
        copyFiles(dir, filesInEachDir);
      }
    };
  })(dirs[i]));
}

...这在技术上等同于使用.forEach,只是看起来不那么容易。

【讨论】:

  • 嗨,感谢您引导我完成此操作。您是否在返回函数之前缺少一些括号。 JS 提示告诉我,它是在您的第二个和第三个示例的底部附近的“预期和赋值或函数调用”。
  • @thomas 哎呀,复制和粘贴故障。现已修复。
  • 您能解释一下(dirs[i]) 被作为另一组括号中的另一个参数提供给fs.mkdir 的情况吗?
  • 另外,将我的两个循环都变成forEach 并没有解决问题。其他两种方法真的相同吗?
  • 那不是“另一组括号”,它是函数调用的参数。稍微考虑一下设置,您就会看到它。 :)
猜你喜欢
  • 1970-01-01
  • 2012-07-20
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
  • 2011-09-27
  • 2020-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多