Anna Klein
Anna Klein

Reputation: 2171

Promise all with inner function to be executed

I want to retrieve different HTML body at once and as soon as all results are available work with that content.

My callback solution which works looks like this (probably only relevant to read if the idea is not clear, otherwise skip ;)):

const request = require('request')

const argLength = process.argv.length
const result_array = []
let counter = 0

function executeRequest () {
  for (start = 2; start <= argLength - 1; start++) {
    const copy = start

    function callback (error, res, body) {
      const startCopy = copy
      if (error) {
        console.log('error')
        return
      }
      result_array[startCopy - 2] = body.toString().length
      counter++
      if (counter === argLength - 2) {
        console.log(result_array)
      }
    }

    request(process.argv[start], callback)
  }
}

executeRequest()

Now I try to make it running with Promises like this:

const httpRequest = require('request')
const argumentLength = process.argv.length

function fillURLArray () {
  resultArray = []
  for (start = 2; start < argumentLength; start++) {
    resultArray[start - 2] = process.argv[start]
  }
  return resultArray
}

const urls = fillURLArray()

let counter = 0

function readHttp () {
  const resultArray = []
  Promise.all(urls.map(url => httpRequest(url, (error, res, body) => {
    console.log(body.toString())
    resultArray[counter++] = body.toString()
  }))).then(value => {
    console.log('promise counter: ' + counter++)
    console.log(resultArray)
    console.log('called')
  })
}

readHttp()

I tried already several attempts with different promise chains but every time I get either not a result or just an empty array. So obviously the .then() function is called before the array is actually filled (at least I guess so since console.log(body.toString()) appears to print the content some time later)

Any idea how to solve this with promises?

Thank you

Upvotes: 1

Views: 40

Answers (2)

front_end_dev
front_end_dev

Reputation: 2056

request is not returning promise object so have created a method that return promise object on which you do Promise.all.

function requestPromise(url){
  return new Promise((resovle,reject) => {
     httpRequest(url, (error, res, body) => {
      if(err){
         reject(err);
      }
      resolve(body.toString());
  });
  });
}


function readHttp () {
  const resultArray = []
  Promise.all(urls.map(url => requestPromise(url))).then(values => {
    console.log("counter => ",values.length);
    resultArray = resultArray.concat(values);
    console.log("values=> ",values);
    console.log("resultArray=> ",resultArray);
  });
}

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138267

httpRequest does not return a promise so you have to make one yourself, also your resultArray is not necessary:

 const makeRequest = url => new Promise((resolve, reject) => httpRequest(url, (error, res) => error ? reject(error) : resolve(res)));

 Promise.all(urls.map(makeRequest))
   .then(result => {         
     console.log(result.map(res => res.body.toString()));
     console.log('called');
   });

Upvotes: 1

Related Questions