Byte Beat Interviewer: Please use JS to achieve Ajax concurrent request control

Byte Beat Interviewer: Please use JS to achieve Ajax concurrent request control

To be honest, I have been very confused recently. About technology, about life. I also found a lot of friends in big factories to talk about, wanting to need some ideas for later development. Among them, I also talked about interviews, and talked about some of the questions that will be given to interviewers during recruitment. It happened that I hadn't interviewed for a long time, so I chose a few of them. Recently, there will be a series of analysis on some interview questions.

Today this is bytedance:

To implement a batch request function multiRequest(urls, maxNum), the requirements are as follows:
• Require the maximum number of concurrent maxNum
• Whenever a request is returned, a space is left and a new request can be added
• After all requests are completed, the results will be typed out in order according to the urls

I think many students have seen this topic more or less. Below, I will give a complete analysis of this topic step by step from the analysis of the scene and the problem to the final realization.

Scenes

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

What should I do?

1. let's look at Ajaxthe serial and parallel.

Realize Ajax serial and parallel based on Promise.all

We usually promiseencapsulate asynchronous requests based on it, and here is also mainly for asynchronous requests.

  • Serial: After an asynchronous request is completed, the next request is made
  • Parallel: multiple asynchronous requests at the same time

promise实例Demonstrate serial/parallel concretely by defining some .

Serial

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 in the example, the serial will execute the corresponding interface requests sequentially from top to bottom.

parallel

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

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

Promise.allIt can be guaranteed promisesthat all promiseobjects in the array reach the resolvestate before the thencallback is executed .

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')
})

Promise.all concurrency limit

Consider a scenario at this time: If promisesevery object in your array is http请求, and there are hundreds of thousands of such objects.

Then it will happen that you send hundreds of thousands in an instant http请求, which is likely to cause countless call stacks to accumulate and cause memory overflow.

At this time, we need to consider Promise.allconcurrency restrictions.

Promise.all并发限制It means that the promisenumber of concurrent executions at each moment is fixed, and the final execution result remains the same as the original one Promise.all.

Topic realization

Thinking analysis

The whole is realized by recursive calls: the maximum number of requests sent initially is the maximum allowed, and each of these requests should continue to be sent recursively upon completion, urlsand the specific one inside is determined by the passed-in index to URLensure that the last The order of output will not be chaotic, but output sequentially.

Code

function multiRequest(urls = [], maxNum) {
 //Total number of requests
  const len ​​= urls.length;
 //Create an array based on the number of requests to save the results of the request
  const result = new Array(len).fill(false);
 //current completed quantity
  let count = 0;

  return new Promise((resolve, reject) => {
   //request maxNum
    while (count <maxNum) {
      next();
    }
    function next() {
      let current = count++;
     //deal with boundary conditions
      if (current >= len) {
       //When the request is completed, the promise is set to a successful state, and then the result is returned as the promise value
        !result.includes(false) && resolve(result);
        return;
      }
      const url = urls[current];
      console.log(`Start${current}`, new Date().toLocaleString());
      fetch(url)
        .then((res) => {
         //save the request result
          result[current] = res;
          console.log(`Complete ${current}`, new Date().toLocaleString());
         //The request is not completed, recursively
          if (current <len) {
            next();
          }
        })
        .catch((err) => {
          console.log(`End${current}`, new Date().toLocaleString());
          result[current] = err;
         //The request is not completed, recursively
          if (current <len) {
            next();
          }
        });
    }
  });
}

Reference: https://cloud.tencent.com/developer/article/1784512 Byte Beat Interviewer: Please use JS to achieve Ajax concurrent request control-Cloud + Community-Tencent Cloud