Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining Promises without using multiple "then's"

I'm learning how to use Promises. I have the following functions that returns the "i"th xkcd comic title as a Promise:

var xkcd = function(i) {
  return new Promise(
    function(resolve, reject) {
      var tempurl = 'https://www.xkcd.com/' + i;
      request(tempurl, function(error, response, body) {
        if (error) reject(error);
        var $ = cheerio.load(body);
        resolve($('title').text() + '\n');
      });
    });
};

If i want to get the first 4 titles, I'm chaining my .then() as such:

var result = '';
xkcd(1)
  .then(fullfilled => {
    result += fullfilled;
  })
  .then(() => xkcd(2))
  .then(fullfilled => {
    result += fullfilled;
  })
  .then(() => xkcd(3))
  .then(fullfilled => {
    result += fullfilled;
  })
  .then(() => xkcd(4))
  .then(fullfilled => {
    result += fullfilled;
    console.log(result);
  });

Is there a more elegant way to do this without chaining this many "then"s? Say if i want to get the first 50 comic titles, i'll have to chain a lot of "then"s.

I can do it without using Promises using recursive callbacks:

function getXKCD(n) {
  var i = 1;
  (function getURL(i){
    var tempurl = 'https://www.xkcd.com/' + i;
    request(tempurl, function(error, response, body) {
      if (error) console.log('error: ' + error);
      var $ = cheerio.load(body);
      //prints the title of the xkcd comic
      console.log($('title').text() + '\n');
      i++;
      if (i <= n) getURL(i);
    });
  })(i);
}

getXKCD(4);

But I'm interested to know if I can do the same with Promises. Thank you.

like image 452
Yeedub Avatar asked Jan 30 '23 15:01

Yeedub


1 Answers

You can push the promises to an array, and then return Promise.all, which would resolve when all the promises have resolved, something like

function getXKCD(_start, _end) {
  if (_end >= _start) return Promise.reject('Not valid!');
  var promises = [];

  (function rec(i) {
    var p = new Promise(function(resolve, reject) {
      request('https://www.xkcd.com/' + i, function(error, response, body) {
        if (error !== null) return reject(error);

        if (i <= _end) rec(++i);
        let $ = cheerio.load(body);
        resolve($('title').text());
      });
    });

    promises.push(p);
  })(_start);

  return Promise.all(promises);
}

getXKCD(1, 50).then(res => { /* All done ! */ }).catch( err => { /* fail */ })
like image 182
adeneo Avatar answered Feb 03 '23 06:02

adeneo