Example code of limiting the number of requests by using js to realize Ajax concurrent requests

  • 2021-11-01 23:46:09
  • OfStack

Description of problems: When the number of asynchronous requests is uncertain, in order to prevent hundreds of http requests from happening in an instant, countless call stacks are piled up, which leads to memory overflow problems.

Requirements: The number of concurrent requests at the same time should be controlled within 3, and the response results should be obtained as quickly as possible.

Same interview question:

Implement a batch request function multiRequest (urls, maxNum) with the following requirements:

Maximum concurrency required maxNum Whenever one request returns, one slot is left to add new requests After all requests are completed, the results are typed in the order in urls

1. Serial and parallel implementation of Ajax based on Promise. all

Usually, asynchronous requests are encapsulated based on promise

Serial: After 1 asynchronous request is completed, make the next request

Parallel: Multiple asynchronous requests are made simultaneously

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

Parallel:


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(promises: []).then(fun: function);

promise. all ensures that all promise objects in the array reach the resolve state before executing the then callback

Promise. all concurrency limit

Meaning: It means that the number of promise executed concurrently at each moment is fixed, and the final execution result remains the same as the original promise. all1.

Thoughts and Realization

It is implemented by recursive call, and the maximum number of requests is set. And every one of these requests should continue to be sent recursively when it is completed, and the specific URL in urls is determined by the incoming index, so as to ensure that the final output order will not be chaotic, but will be output in turn

Code implementation:


function multiRequest(urls = [], maxNum) {
 //  Total number of requests 
 const len = urls.length;
 //  Based on the number of requests 1 Array to hold the result of the request 
 const result = new Array(len).fill(false);
 //  Quantity currently completed 
 let count = 0;

 return new Promise((resolve, reject) => {
  //  Request maxNum A 
  while (count < maxNum) {
   next();
  }
  function next() {
   let current = count++;
   //  Dealing with boundary conditions 
   if (current >= len) {
    //  When the request is completed, the promise Set to Success Status ,  Then the result As promise Value return 
    !result.includes(false) && resolve(result);
    return;
   }
   const url = urls[current];
   console.log(` Begin  ${current}`, new Date().toLocaleString());
   fetch(url)
    .then((res) => {
     //  Save the request result 
     result[current] = res;
     console.log(` Finish  ${current}`, new Date().toLocaleString());
     //  The request was not fully completed ,  Just recursion 
     if (current < len) {
      next();
     }
    })
    .catch((err) => {
     console.log(` End  ${current}`, new Date().toLocaleString());
     result[current] = err;
     //  The request was not fully completed ,  Just recursion 
     if (current < len) {
      next();
     }
    });
  }
 });
}

Code implementation:


  //  Task list -> New Task 
 
  uploadFile() {
   let _this = this;
   var uploadThreadLimitNums = 3,
    uploadThreadNums = 0,
    sendFinishNum = 0,
    resultFinishNum = 0;
   var marks = 0;
   var tasks = [];
   var upload = function () {
    while (uploadThreadNums < uploadThreadLimitNums) {
     if (sendFinishNum >= _this.fileList.length) {
      if (resultFinishNum >= _this.fileList.length) {
       creatTask(); //  Complete the request 
      }
      return;
     }
     (function (j) {
      let item = _this.fileList[j];
      let p = new FormData();
      p.append("file", item);
      tasks.push(
       axios({
        method: "post",
        url: `${window.UL_CONFIG.BASEURL}/api/files/upload`,
        data: p,
        onUploadProgress: (progressEvent) => {
         for (let i in _this.rowData) {
          _this.rowData[i].name === item.name
           ? (_this.rowData[i].percent = Math.round(
             (progressEvent.loaded / progressEvent.total) * 100
            ))
           : "";
         }
        },
       })
        .then((res) => {
        /* let obj = {};
         obj.url = `${window.UL_CONFIG.BASEURL}/api/files/${res.data}`;
         obj.fileName = item.name;
         obj.fmt = _this.ruleForm.format;
         obj.samplingRate = _this.ruleForm.samplingRate;
         fileUrls.push(obj); */
        })
        .catch((e) => {
           ? (_this.rowData[i].percent = 0)
         _this.$notify.error({
          title: " Errors ",
          message: " Service connection error  " + item.name + "  Unuploaded successfully ",
         });
        .finally(() => {
         uploadThreadNums--;
         resultFinishNum++;
         upload();
      );
     })(sendFinishNum);
     uploadThreadNums++;
     sendFinishNum++;
    }
   };
   var creatTask = function () {
    axios.all(tasks).then((res) => {
     //  New Upload Task 
      /* let fd1, fd2, calcFlag, flagArr, language;
     fd1 = {};
     flagArr = Object.assign([], _this.ruleForm.checkList);
     if (_this.ruleForm.recognize == " Automatic identification ") {
      flagArr.push("2");
     calcFlag = flagArr.reduce(
      (accu, curr) => Number(accu) + Number(curr)
     );
     _this.ruleForm.recognize == " Automatic identification "
      ? (language = "")
      : (language = _this.ruleForm.recognize);
     fd1.processContent = calcFlag;
     fd1.remark = _this.ruleForm.remark;
     fd1.name = _this.ruleForm.taskName;
     fd1.fmt = _this.ruleForm.format;
     fd1.samplingRate = _this.ruleForm.samplingRate;
     fd1.language = language;
     fd1.type = 1; // type: 1  Voice , 2  Video 
     fd1.files = fileUrls; */
     newTask(fd1).then((res) => {
      /* _this.cmpltBtnState = false;
      _this.$store.commit("setTaskId", res.data.id);
      _this.submitFailNumber = res.data.submitFailNumber; */
      _this.$parent.dataInit();
     });
    });
   upload();
  },

Related articles: