skip to Main Content

I issue blocks of 5 REST api calls which I then save in an array – promiseArray.
I then issue a Promise.all(promiseArray.then((result) => {...}
Then I start my next block of 5 REST api calls.

There can be many REST calls involved and I limit them to 5 so as to not overload the server.
This is all working fine but I am having to wait for all 5 to be resolved before proceeding and I would ideally like to detect when any REST call resolves so I can then issue my next REST call – in order to maintain 5 running at a time.
So far I have not been able to determine how to do this.

As a test, I have tried adding .then((result) => {...}
but it doesn’t fire until it hits my existing Promise.all(.promiseArray) statement – which I am trying to replace!

My second problem is that I need to know which particular REST call is resolved within my array of 5. As I then need to insert my next REST call into the promiseArray at that same offset.
That is necessary because my REST call contains a token which cannot be used across calls concurrently, so I assign the token from a parallel token array using the offset value.

I would appreciate any suggestions.

3

Answers


  1. Instead, you should create 5 promises that each runs a while-loop picking out elements from a list and turning them into API calls (like a queue).

    I am not sure how this would work with the situation mentioned in your second problem. If I’m understanding correctly, you have 5 tokens that can be used for authorizing with the API? In that case you can just use one token for each of the 5 promises.

    Login or Signup to reply.
  2. You can create a function (queueManager) which is picks up a piece of data from a queue and passes it to your function which creates the promise (processor).

    When processor‘s promise resolves, queueManager can call itself recursively to pull the next piece of data from the queue, create a new promise and return that.

    If the resolved value is another promise, then that promise will get adopted.

    At some point the queue will run out of data, so at that point you should just resolve the promise with a regular value (or nothing) so that the recursion stops.


    Once you have a queueManager, you can run multiple of them in parallel so that you have (for example) 5 things from the queue being worked on at once.

    Then you can put those 5 queueManager promises into an array and pass it to Promise.all so you know when they are all finished.

    const dataQueue = [5000, 4000, 3000, 2000, 1000, 1000, 2000, 3000, 4000, 5000, 3000, 2000, 4000, 1000, 5000];
    
    const results = [];
    
    const processor = (data) => {
      console.log(`Starting with ${data}`);
      return new Promise(resolve => {
        setTimeout(() => {
          console.log(`Finished with ${data}`);;
          resolve(`Data was ${data}`)
        }, data)
      });
    }
    
    const queueManager = async() => {
      if (dataQueue.length === 0) {
        return Promise.resolved();
      }
      const input = dataQueue.shift()
      const output = await processor(input);
      results.push(output);
      return queueManager();
    }
    
    Promise.all([queueManager(), queueManager(), queueManager(), queueManager(), queueManager()]).then(() => console.log(results));
    Login or Signup to reply.
  3. The code below initially invokes the function scheduleNextRequest 5 times with 5 different tokens and then again whenever a previous request has been completed, using the same token in the new request as in the completed one. This guarantees that there are 5 requests running with different tokens at all times (until makeNextRequest returns false, because there is nothing more to do).

    var total = 0;
    
    function makeNextRequest(token) {
      return !done.checked && new Promise(function(resolve, reject) {
        setTimeout(resolve, 1000 * Math.random());
      });
    }
    
    function scheduleNextRequest(token) {
      var req = makeNextRequest(token);
      if (req) {
        document.getElementById(token).checked = true;
        totalCounter.textContent = ++total;
        req.then(function() {
          document.getElementById(token).checked = false;
          scheduleNextRequest(token);
        });
      }
    }
    
    scheduleNextRequest("token1");
    scheduleNextRequest("token2");
    scheduleNextRequest("token3");
    scheduleNextRequest("token4");
    scheduleNextRequest("token5");
    <input type="checkbox" id="token1" />
    <input type="checkbox" id="token2" />
    <input type="checkbox" id="token3" />
    <input type="checkbox" id="token4" />
    <input type="checkbox" id="token5" />
    <span id="totalCounter"></span>
    <input type="checkbox" id="done" /> All done

    (This example does not make real requests, it simulates them by waiting for a random period.)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search