Home > Enterprise >  Promise all to speed up api call in for loop - javascript
Promise all to speed up api call in for loop - javascript

Time:12-17

I have the following for loop which works correctly in my code. However it needs to do multiple api calls as it loops through, which is taking a long time, so i am trying to figure out whether i could do a promise all and run the api calls all at once.

But really not sure how to go about it, with how my code works, so hoping someone might be able to help.

Below is my code:

let terms = []
this.selectedGroup.groups = ['A', 'B', 'C', 'D', 'E', 'F']

//loop through each term
for (let term of this.terms) {
  let subjects: any = [];

  //loop through each terms assessments
  for (let assessment of term.assessments) {

    //loop through the assessment year groups
    for (let assessmentGroup of assessment.year_groups) {

      //only get the assessments for the particular year group we are looking at
      if (this.selectedGroup.groups.includes(assessmentGroup.name)) {

        //get the subject data for this assessment
        let newSubjects = await this.dataService.getData(
          assessment,
          assessmentGroup,
          this.selectedGroup.students
        );

        //add the assessment subjects to the overall subjects array
        subjects = subjects.concat(newSubjects)
      }
    }
  }

  //push all the subjects for the term into a terms array
  terms.push({
    name: term._id,
    subjects: subjects,
  });
}

Is there anyway of introducing a promise all to this, so the api calls can run at once? Thanks in advance!

CodePudding user response:

Here are the steps to take:

  1. Remove the await keyword where you currently have it. So now subjects will be an array of promises.

  2. Add await Promise.all in your push call:

    terms.push({
        name: term._id,
        subjects: (await Promise.all(subjects)).flat(),
    });
    

That's it: now there will multiple pending promises until one item is pushed to the terms array. This should already give some improvement.

If you want to have even more simultaneous pending promises, then also make terms an array of promises:

terms.push(Promise.all(subjects).then(subjects => ({
    name: term._id,
    subjects: subjects.flat(),
})));

And then, after the outermost loop, have a one-for-all await:

terms = await Promise.all(terms);

CodePudding user response:

You can put the this.dataService.getData call in a array and in the of the assessment.year_groups loop resolve all promises with Promises.all method.

let terms = []
let promises = [];
this.selectedGroup.groups = ['A', 'B', 'C', 'D', 'E', 'F']

//loop through each term
for (let term of this.terms) {
  let subjects: any = [];

  //loop through each terms assessments
  for (let assessment of term.assessments) {

    //loop through the assessment year groups
    for (let assessmentGroup of assessment.year_groups) {

      //only get the assessments for the particular year group we are looking at
      if (this.selectedGroup.groups.includes(assessmentGroup.name)) {

        //get the subject data for this assessment
         promises.push(this.dataService.getData(
          assessment,
          assessmentGroup,
          this.selectedGroup.students
        ));
      }
    }
   Promise.all(promises).then(v => subjetcs.concat(v)) # resolve the promise here
  }

  //push all the subjects for the term into a terms array
  terms.push({
    name: term._id,
    subjects: subjects,
  });

  • Related