Nodejs在使用Loop下载许多文件时丢失了数据

Nodejs lost data when using Loop for download many files

本文关键字:数据 文件 许多 Loop 下载 Nodejs      更新时间:2023-09-26

今天,我试图从我的服务器下载许多文件

下载.js

function getPhotos(req, res) {
  //Get User Photos
  var fileReader = fs.readFile('./../data/user.json', 'utf8', function(err, data) {
    if (err)
      console.log(err);
    else {
      var dataJson = JSON.parse(data);
      //console.log(dataJson.Person);
      for (var i = 0; i < dataJson.Person.length; i++) {
        var options = {
          host : '10.16.47.128', // Local Server IPAddress
          port : 2013, //Port
          path : '/ExternalServer/avatar/' + dataJson.Person[i].Username + '.jpg',
        };
        //console.log(dataJson.Person[i].Username);
        var fileAvatarPhotos = fs.createWriteStream('./../avatar/' + dataJson.Person[i].Username + '.jpg');
        fs.exists(fileAvatarPhotos, function(exists) {//Check Exist File
          if (exists) {
            var req = http.get(options, function(res) {
              //console.log(res);
              res.pipe(fileAvatarPhotos);
            });
          } else {
            var req = http.get(options, function(res) {
              fs.writeFile(fileAvatarPhotos, '', function(err) {
                if (err)
                  return console.log(err);
                var req = http.get(options, function(res) {
                  //console.log(res);
                  res.pipe(fileAvatarPhotos);
                });
              });
            });
          }
        });
      }
    }
  });
  //End Get User Photos
}

当我运行代码时:

node download.js

系统下载了所有照片,但照片大小为0kb。并且有错误:

stream.js:81投掷者;//管道中出现未处理的流错误。^错误:OK,关闭

此外,当我抛出循环时(例如:修复dataJson.Person[I].Username,将I更改为10)

运行代码后,系统重新生成正确的照片。

发生了什么?如何修复?

致以最崇高的敬意。!

在for循环中实现这样的功能不是一个好主意。这是因为在循环中有异步操作,但循环的每一次迭代都会立即执行。在您的案例中,您正在定义fileAvatarPhotos,它是一个WriteStream对象。http.get方法是异步的,因此在其回调中,您可以使用为循环的第三次迭代、第四次迭代或第一次迭代定义的fileAvatarPhotos。这取决于情况。你可以尝试将你的代码转换成这样的东西:

var files = ["file1.jpg", "file2.jpg", "file3.jpg"];
var readFile = function(callback) {
    if(files.length > 0) {
        var file = files.shift();
        http.get({path: file}, function(res) {
            // ... process the result
            readFile(callback);
        })
    } else {
        callback();
    }
}
readFile(function() {
    console.log("reading finishes");
});

即,一次又一次地调用readFile,直到files数组中不再有元素为止。

Javascript没有循环块作用域,它有基于函数的作用域。

这意味着,正如Krasimir所指出的,for循环变量正在相互覆盖在它们被使用完之前。

所以,你至少需要把for循环的内部结构包裹在一个函数中,或者看起来奇怪的事情就会开始发生。

即使这种情况得到了解决,代码也会尝试同时进行所有下载,而Krasimir的答案可能更清晰,因为他避免了这种情况。

尽管如此,使用一个函数来确保每个for循环执行都有自己的作用域是知道这件事是件好事。

循环修改如下:

for (var i = 0; i < dataJson.Person.length; i++) {
      (function(i){
        var options = {
          host : '10.16.47.128', // Local Server IPAddress
          port : 2013, //Port
          path : '/ExternalServer/avatar/' + dataJson.Person[i].Username + '.jpg',
        };
        //console.log(dataJson.Person[i].Username);
        var fileAvatarPhotos = fs.createWriteStream('./../avatar/' + dataJson.Person[i].Username + '.jpg');
        fs.exists(fileAvatarPhotos, function(exists) {//Check Exist File
          if (exists) {
            var req = http.get(options, function(res) {
              //console.log(res);
              res.pipe(fileAvatarPhotos);
            });
          } else {
            var req = http.get(options, function(res) {
              fs.writeFile(fileAvatarPhotos, '', function(err) {
                if (err)
                  return console.log(err);
                var req = http.get(options, function(res) {
                  //console.log(res);
                  res.pipe(fileAvatarPhotos);
                });  // http.get
              }); // fs.writeFile
            }); // http.get
          } // else 
        }); // fs.exists
       })(i); // anonymous function to create scopes for loop
      } //for loop