Search code examples
javascriptasynchronouses6-promise

Promises.all not fired after looping through multiple ajax requests


I'm importing a json file and loop through the object. Each object has an array with eventIDs, which I loop through as well. In this forEach I push a wrapper function that returns a Promise into an array promises

After looping through all objects I perform a promise.all() on the promises array. But strangely anything I do after this loop is not executed.

const fs = require('fs')
const promisify = require('util').promisify
const rp = require('request-promise')
const readFile = promisify(fs.readFile)
const filePath = 'json/results.json'

let promises = []

function init() {
  readFile(filePath, 'utf8')
  .then(file => {
    const json = JSON.parse(file)

    for (const country of json) {
      if (country.eventIDs.length === 0) return

      country.eventIDs.forEach(id => promises.push(getEventData(country, id)))
    }

// nothing here is executed,  
    console.log('this is not fired')

    Promise.all(promises)
           .then(results => writeFile(results))
           .catch( err => console.log(err))
  })
  .catch(err => console.log(err))
}

getEventData = (country, id) => new Promise((resolve, reject) => {

  setTimeout(() => {
    rp(url)
    .then((results) => {      
      resolve ({
        ...results
      })
    })
    .catch((err) => reject(`getEventData Error:\n ${err}`))
  }, 2000)
})

writeFile = (results) => {
  const json = JSON.stringify(results)
  // const date = new Date()
  // const filename = `${date.getTime()}-all-event-ids.json`
  const filename = `results-allevents.json`
  fs.writeFile(`json/${filename}`, json, 'utf8', () => console.log(`Succesfully written: ${filename}`))
}

init()

Solution

  • After the investigation, the line:

    if (country.eventIDs.length === 0) return

    was the main issue (and many others solved through comments).

    The issue, to explain that, is that the return is not skipping the looped item (as perhaps expected), but rather returning void in the then callback, so skipping further executions of that block.

    In order to "skip" the item if that condition is true, just do this instead

        for (const country of json) {
          if (country.eventIDs.length > 0) { 
              country.eventIDs.forEach(id => promises.push(getEventData(country, id))) 
          }
        }