在传递给函数之前,for循环递增到限制

时间:2015-07-22 22:18:05

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

我有一些代码可以复制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

1 个答案:

答案 0 :(得分:4)

你有一个经典问题是在异步函数上使用for循环引起的:循环在它调用的任何函数之前很久完成,所以当第一个函数实际开始做某事时,循环索引它指的是已被覆盖。

请改用.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循环在外部控制。您需要一个本地数组索引。

您可以使用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,这在眼睛上并不那么容易。