26

I've got a following piece of code

var page = 2;
var last_page = 100;
while(page <= last_page) {
  request("http://some_json_server.com/data?page=" + page, function (error, response, body) {
    if (!error && response.statusCode == 200) {
      store_data(body)
    }
    page++;
  });                
}

I've done the following, but it is actually not retrieving anything. Am I doing this correctly?

var page = 2;
var last_page = 100;
while(page <= last_page) {
var async_arr = [];
async_arr.push(
  function(next) {
    request("http://some_api_url?page=" + page, function (error, response, body) {
      if (!error && response.statusCode == 200) {
        store_data(body);
      }
    });
  }
);

async.series(
  async_arr, done
);
2
  • github.com/caolan/async#series Commented Apr 9, 2013 at 12:44
  • 2
    Regarding your edit, you have to call next() in the request callback Commented Apr 9, 2013 at 13:03

3 Answers 3

55

With while you get a busy loop, which is counter-purpose in Node.

Make it a recursive function instead. Each call will be done in a separate tick.

var page = 2;
var last_page = 100;

(function loop() {
    if (page <= last_page) {
        request("/data?page=" + page, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                store_data(body)
            }
            page++;
            loop();
        });
    }
}());
Sign up to request clarification or add additional context in comments.

7 Comments

+1 What if you didn't know the number of pages? How would you handle this @katspaugh
@TheGrayFox, the response should somehow indicate either the number of pages, or just send you no data so you know you shouldn't make the next request.
A recursive function will eventually eat up all of your memory and you will exceed your call stack size.
@katspaugh assuming the use case never exceeds page 100 it will probably not cause any problems and its recursion only occurs inside of the request callback it will probably not cause issue. Just something good to note if you plan on using this pattern.
I think you should look into using the http agent. nodejs.org/api/http.html#http_new_agent_options I've found that you can get far better control over large number of http requests by using the agent as a custom request pool.
|
25

You're looking for async.whilst(). This solution is assuming you actually want to do each request after the other. As @UpTheCreek mentions (edit: the comment I referred to was edited) it would likely be possible to do it asynchronously and keep track of each result using async.parallel.

var page = 2,
    lastPage = 100;

async.whilst(function () {
  return page <= lastPage;
},
function (next) {
  request("http://some_json_server.com/data?page=" + page, function (error, response, body) {
    if (!error && response.statusCode == 200) {
      store_data(body)
    }
    page++;
    next();
  });
},
function (err) {
  // All things are done!
});

1 Comment

Damn, I wish you had answered my question I just asked just now. I think this is exactly what I'm looking for.
0

You can also wrap your while loop in async and break after your promise resolves/conditions have been met...

    const request = require("request")

    ;(async()=>{

    let results = []
    while(true){
      await new Promise(resolve => {
        request('http://www.seanbehan.com/', (err, resp, body)=>{
          console.log(new Date, 'Downloading..')
          results.push(body)
          resolve(body)
        })
      })

      if(results.length >= 5){
        break
      }
    }

    console.log(results)
  })()

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.