How does JavaScript use promise to control the number of concurrent requests

Time:2021-10-11

1、 Scene

Suppose there is such a scenario: there are 30 asynchronous requests to be sent, but for some reasons, we must control the number of concurrent requests at the same time within 5, and get the response results as quickly as possible.

As shown in the figure:

The queuing in the above figure is basically similar to the scenario of concurrent requests. There are only three windows. When there are more than three people, the people behind can only queue.

2、 Serial and parallel

  • Serial: after an asynchronous request is completed, the next request is made
  • Parallel: multiple asynchronous requests occur simultaneously

Serial example:


var p = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("1000");
      resolve();
    }, 1000);
  });
};
var p1 = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("2000");
      resolve();
    }, 2000);
  });
};
var p2 = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("3000");
      resolve();
    }, 3000);
  });
};

p()
  .then(() => {
    return p1();
  })
  .then(() => {
    return p2();
  })
  .then(() => {
    console.log("end");
  });

As an example, the serial will execute the corresponding interface request from top to bottom.

Parallel examples:

Generally, when we need to ensure that the code is executed after multiple asynchronous processes, we will use:


Promise.all((promises: [])).then((fun: function));

Promise.all can ensure that all promise objects in the promises array reach the resolve state before executing the then callback.


var promises = function () {
  return [1000, 2000, 3000].map((current) => {
    return new Promise(function (resolve, reject) {
      setTimeout(() => {
        console.log(current);
      }, current);
    });
  });
};

Promise.all(promises()).then(() => {
  console.log("end");
});

Consider a scenario:

If each object in your promises array is an HTTP request, there are hundreds of thousands of such objects.
In that case, you will send hundreds of thousands of HTTP requests in an instant, which may lead to the accumulation of countless call stacks and memory overflow.
At this time, we need to consider limiting the concurrency of promise.all.
Promise.all concurrency limit means that the number of promises executed concurrently at each time is fixed, and the final execution result remains consistent with the original promise.all.

3、 Code implementation

Recursive call is used to realize the whole: the upper limit of the number of requests initially sent is the maximum allowed, and each of these requests should continue to be sent recursively when completed. The specific URL in URLs is determined through the incoming index to ensure that the final output order will not be disordered, but output in turn.

code:

function multiRequest(urls, maxNum) {
 const len = urls.length; //  Total number of requests
 const res = new Array(len).fill(0); //  Request result array
 let sendCount = 0; //  Number of requests sent
 let finishCount = 0; //  Number of requests completed
 return new Promise((resolve, reject) => {
     //First, send maxnum requests. Note: the number of requests may be less than maxnum, so condition 2 must also be met
     //Create maxnum next parallel requests synchronously, and then execute asynchronous fetches, so there are five next parallel requests
     while (sendCount < maxNum && sendCount < len) { 
         next();
     }
     function next () {
         let current = sendCount ++; //  The number of requests currently sent, plus the location where the current request URL is saved
         //Recursive exit
         if (finishCount >= len) { 
         //If all requests are completed, resolve promise and terminate the recursion
             resolve(res);
             return;
         }
         const url = urls[current];
         fetch(url).then(result => {
             finishCount ++;
             res[current] = result;
             If (current < len) {// if the request is not sent, continue to send the request
                 next();
             }
         }, err => {
             finishCount ++;
             res[current] = err;
             If (current < len) {// if the request is not sent, continue to send the request
                 next();
             }
         });
     }
 });
}

Summary:

The code creates maxnum “request windows” at the while loop to make requests, so as to achieve the parallel effect. Then, it makes asynchronous requests in the next function, and then recursively calls new requests in. Then to realize “only one request is made in a window, and the next request is made after the execution of this request is completed” (each window is executed serially, and maxnum windows are executed in parallel).

This is the end of this article on how JavaScript uses promise to control the number of concurrent requests. For more relevant JS using promise to control concurrent requests, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!

Reference link

1、https://www.jb51.net/article/211898.htm

2、https://www.jb51.net/article/212277.htm