2

Today, I'm try to download many file from my server

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
}

when I run code:

node download.js

System downloaded all photos, but size of photo is 0kb. and has error:

stream.js:81 throw er; // Unhandled stream error in pipe. ^ Error: OK, close

Beside, when I Throw Loop (EX: fix dataJson.Person[i].Username, change i to 10)

after running code, system reurn correct photo.

what are happening? How to fix it?

best regard.!

2 Answers 2

7

It's not a good idea to implement such a functionality in a for loop. That's because inside the loop you have async operations, but every iteration of the loop is executed immediately. In your case you are defining fileAvatarPhotos which is a WriteStream object. The http.get method is asynchronous, so in its callback you may use the fileAvatarPhotos defined for the third iteration of the loop, or the fourth or maybe the first one. It depends. You may try to convert your code to something like this:

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");
});

I.e. readFile is called again and again till there is no more elements in files array.

Sign up to request clarification or add additional context in comments.

Comments

3

Javascript doesn't have loop block scopes, it has function-based scopes.

That means, as Krasimir points out, that your for-loop variables are overwriting each other before they are finished being used.

So, you need to at least wrap the innards of that for loop in a function, or things that seem strange will start happening.

Even if that is fixed, the code will be trying to do all the downloads at the same time, and Krasimir's answer may be cleaner since he avoids that.

Still, using a function to make sure each for-loop execution gets its own scope is a good thing to know.

Modify for loop as follows:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.