Search code examples
javascriptasync-awaitpromisesettimeout

Promise.all on multiple dynamic timeouts


I am trying to figure out the best way to wait until all my 'setTimeout' functions are done before I move on to the next action in my code but I can't find a way to do it.

Tried to extract a function to generate a list of promises for which I can wail until all are resolved, but something is not working out well.

ngOnInit() {
    if (this.item) {
      this.flag = true;
      let p = Promise.all(this.helperFunc(this.item));
      this.flag = false;
    }
}

helperFunc(data) {
  data.forEach((word: any[]) => {
    word.forEach((item: any) => {
      new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(item.letter);
          resolve(true);
        }, item.timing);
      });
    });
  });
}

Here is an example of the dataset that may get to the 'helperFunc' function:

[
  [
    {
      "letter": "S",
      "timing": 500
    },
    {
      "letter": "e",
      "timing": 765
    },
    {
      "letter": "a",
      "timing": 1113
    },
    {
      "letter": "r",
      "timing": 1418
    },
    {
      "letter": "c",
      "timing": 1744
    },
    {
      "letter": "h",
      "timing": 1874
    },
    {
      "letter": "i",
      "timing": 1985
    },
    {
      "letter": "n",
      "timing": 2176
    },
    {
      "letter": "g",
      "timing": 2304
    }
  ],
  [
    {
      "letter": " ",
      "timing": 2408
    },
    {
      "letter": "f",
      "timing": 3769
    },
    {
      "letter": "o",
      "timing": 3869
    },
    {
      "letter": "r",
      "timing": 3957
    }
  ],
  [
    {
      "letter": " ",
      "timing": 4092
    },
    {
      "letter": "t",
      "timing": 4226
    },
    {
      "letter": "h",
      "timing": 4329
    },
    {
      "letter": "e",
      "timing": 4433
    }
  ],
  [
    {
      "letter": " ",
      "timing": 4545
    },
    {
      "letter": "s",
      "timing": 5141
    },
    {
      "letter": "o",
      "timing": 5245
    },
    {
      "letter": "l",
      "timing": 5733
    },
    {
      "letter": "u",
      "timing": 6123
    },
    {
      "letter": "t",
      "timing": 6399
    },
    {
      "letter": "i",
      "timing": 6507
    },
    {
      "letter": "o",
      "timing": 6583
    },
    {
      "letter": "n",
      "timing": 6743
    }
  ]
]

The flag never changes to 'false'.

Appreciate the help :)


Solution

  • you must pass an array of promises to the Promise.all function.

    You can use p.then(...) to run code whenever all the promises will be resolved

    ngOnInit() {
        if (this.item) {
          this.flag = true;
          const promises = this.createPromises(this.item);
          Promise.all(promises).then(() => this.flag = false);
        }
    }
    
    private createPromises(data: any[]) {
      return data.flatMap(word => word.map(item => this.createPromise(item)));
    }
    
    private createPromise(word: any) {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log(word.letter);
          resolve(true);
        }, word.timing);
      });
    }