使用循环下载许多文件时,Nodejs丢失了数据

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

download.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扔呃; //在pipe道中未处理的stream错误。 ^错误:确定,closures

另外,当我扔圈(EX:修复dataJson.Person [我]。用户名,改我为10)

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

发生了什么? 如何解决它?

最好的问候。!

在for循环中实现这样的function并不是一个好主意。 这是因为在循环内部有asynchronous操作,但循环的每一次迭代都会立即执行。 在你的情况下,你正在定义fileAvatarPhotos是一个WriteStream对象。 http.get方法是asynchronous的,所以在它的callback函数中,可以使用为循环的第三个迭代定义的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被一次又一次地调用,直到文件数组中没有更多的元素。

Javascript没有循环块范围,它有基于函数的范围。

这就意味着,正如Krasimir所指出的那样,你的for循环variables在完成使用之前会相互覆盖。

所以,你至less需要在一个函数中包装循环的内部,否则就会出现一些奇怪的事情。

即使这是固定的,代码也会试图同时做所有的下载,克拉西米尔的答案可能会更清洁,因为他避免了这一点。

尽pipe如此,使用一个函数来确保每个for循环执行得到它自己的范围是一件好事情要知道。

如下修改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