Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping with Promises

I'm in a scenario where I have to get data from the server in parts in sequence, and I would like to do that with the help of Promises. This is what I've tried so far:

function getDataFromServer() {
  return new Promise(function(resolve, reject) {
    var result = [];

    (function fetchData(nextPageToken) {

      server.getData(nextPageToken).then(function(response) {
        result.push(response.data);
        if (response.nextPageToken) {
          fetchData(response.nextPageToken);
        } else {
          resolve(result);
        }
      });

    })(null);

  });
}

getDataFromServer().then(function(result) {
  console.log(result);
});

The first fetch is successful, but subsequent calls to server.getData() does not run. I presume that it has to do with that the first then() is not fulfilled. How should I mitigate this problem?

like image 530
Tholle Avatar asked Jul 22 '15 22:07

Tholle


People also ask

How to use promise inside a for each loop?

The Promise.allmethod returns a promise when all the promises inside the promisesarray is resolved. So, this is how you can use promise inside a for each loop. A similar approach can be applied to use promise inside for loop or while in JavaScript or Node.js.

What is a promise-looping function?

The function itself returns a promise that allows you to wait until the loop has finished and the handler function that you pass may also return a promise. It took me some time to get it right, but I believe the following code will be usable in a lot of promise-looping situations.

What is a promise2 in JavaScript?

This second promise ( promise2) represents the completion not just of doSomething (), but also of the successCallback or failureCallback you passed in, which can be other asynchronous functions returning a promise.

Can I wrap a setTimeout function in a promise?

Luckily we can wrap setTimeout in a promise. Best practice is to wrap problematic functions at the lowest possible level, and then never call them directly again: const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); wait(10*1000).then(() => saySomething("10 seconds")).catch(failureCallback);


1 Answers

Nimrand answers your question (missing catch), but here is your code without the promise constructor antipattern:

function getDataFromServer() {
  var result = [];

  function fetchData(nextPageToken) {
    return server.getData(nextPageToken).then(function(response) {
      result.push(response.data);
      if (response.nextPageToken) {
        return fetchData(response.nextPageToken);
      } else {
        return result;
      }
    });
  }
  return fetchData(null);
}

getDataFromServer().then(function(result) {
  console.log(result);
})
.catch(function(e) {
  console.error(e);
});

As you can see, recursion works great with promises.

var console = { log: function(msg) { div.innerHTML += "<p>"+ msg +"</p>"; }};

var responses = [
  { data: 1001, nextPageToken: 1 },
  { data: 1002, nextPageToken: 2 },
  { data: 1003, nextPageToken: 3 },
  { data: 1004, nextPageToken: 4 },
  { data: 1005, nextPageToken: 0 },
];

var server = {
  getData: function(token) {
    return new Promise(function(resolve) { resolve(responses[token]); });
  }
};

function getDataFromServer() {
  var result = [];

  function fetchData(nextPageToken) {
    return server.getData(nextPageToken).then(function(response) {
      result.push(response.data);
      if (response.nextPageToken) {
        return fetchData(response.nextPageToken);
      } else {
        return result;
      }
    });
  }
  return fetchData(0);
}

getDataFromServer().then(function(result) {
  console.log(result);
})
.catch(function(e) { console.log(e); });
<div id="div"></div>
like image 200
jib Avatar answered Oct 16 '22 08:10

jib