4

I've been trying to get this working, but I don't seem to understand why it doesn't output the right info. what I get in the console is "page: 6" 5 times, but what I want is page 1, page 2, page 3, page 4, page 5.

for (var i = 1; i <= 5; i++) {
    lib.request({
        path: '/channels/staffpicks/videos',
        query: {
            page: i,
            per_page: 50
        }
    }, function (error, body, status_code, headers) {
        if (error) {
            console.log('error');
            console.log(error);
        } else {
            var totalbody = body.total;
            console.log('page: ' + i);
        }
    });
}
Kuja
  • 449
  • 6
  • 20
  • 2
    Possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Patrick Evans May 08 '16 at 19:26

1 Answers1

5

You should wrap your code within an IIFE to make your variable persist.

for (var i = 1; i <= 5; i++) {
  (function(i) {
     lib.request({
       path: '/channels/staffpicks/videos',
       query: {
         page: i,
         per_page: 50
       }
     }, function (error, body, status_code, headers) {
       if (error) {
         console.log('error');
         console.log(error);
       } else {
         var totalbody = body.total;
         console.log('page: ' + i);
       }
   });
 })(i);
}

The "problem" with your current code is that the callback passed to request() isn't fired instantly, therefore when it is called, it gets the "current i" which is 6.

There are 2 easy solutions to have requests' callbacks fired in order.

First solution - call the request after each other.

(function request(i) {
 lib.request({
   path: '/channels/staffpicks/videos',
   query: {
     page: i,
     per_page: 50
   }
 }, function (error, body, status_code, headers) {
   if (error) {
     console.log('error');
     console.log(error);
   } else {
     var totalbody = body.total;
     console.log('page: ' + i);
   }
   request(++i);
 });
})(0);

Second - a bit more advanced, but also a better one, because the requests are made at the same time.

var amount = 5, 
    fetched = 0,
    results = new Array(amount);
for (var i = 1; i <= amount; i++) {
 (function(i) {
     lib.request({
       path: '/channels/staffpicks/videos',
       query: {
         page: i,
         per_page: 50
       }
     }, function (error, body, status_code, headers) {
       fetched++;
       if (error) {
         console.log('error');
         console.log(error);
         results[i] = "error";
       } else {
         results[i] = body;
         var totalbody = body.total;
       }
       if (fetched === amount) {
         results.forEach(function(body, n) {
           console.log('page: ' + n);
        });
      }
   });
 })(i);
}

There are better solutions though, but they are a bit more complicated.

Jakub Rożek
  • 2,110
  • 11
  • 12
  • 1
    Thanks for the explanation! Is there a reason for the console.log('page: ' + i) not to be in order? the outputs I get varies from time to time, it outputs all the numbers between 1 and 5, but not in order. – Kuja May 08 '16 at 19:35
  • 1
    It depends on when the function is triggered. There is no order, when it fires when the loop is ended, you are likely to get 6. If you want to have "i" specified you must wrap it within such a function. – Jakub Rożek May 08 '16 at 19:41
  • 1
    Not sure if I explained myself well enough, but I don't seem to fully understand your response. I'm using your code snippet now and it works, I'm getting the output I was looking for, except that it's not in order. Is there a way to get it in order? instead of a random order I want it to be 1,2,3,4 etc. – Kuja May 08 '16 at 19:50
  • 1
    Now, I know what you mean. Well the function you call is asynchronous - this means its callback may fire in any order. If you want to get responses in order, the easiest way is to call it one by one. If you are unsure how to do it, I may provide you a simple example. – Jakub Rożek May 08 '16 at 20:13
  • 1
    would love a simple example. – Kuja May 08 '16 at 20:21
  • 1
    Appreciate it alot, Thank you! – Kuja May 08 '16 at 20:50