其他分享
首页 > 其他分享> > 利用js实现Ajax并发请求限制请求数量

利用js实现Ajax并发请求限制请求数量

作者:互联网

 

出现问题描述:当不确定异步请求个数时,为防止当一瞬间发生上百个http请求时,导致堆积了无数调用栈进而导致内存溢出问题。

要求:将同一时刻并发请求数量控制在3个以内,同时还要尽可能快速的拿到响应的结果。

同面试问题:

实现一个批量请求函数 multiRequest(urls, maxNum),要求如下:
• 要求最大并发数 maxNum
• 每当有一个请求返回,就留下一个空位,可以增加新的请求
• 所有请求完成后,结果按照 urls 里面的顺序依次打出

1、基于Promise.all实现Ajax的串行和并行

平时都是基于promise来封装异步请求的

串行:一个异步请求完成了之后再进行下一个请求

并行:多个异步请求同时进行

示例:串行

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

 并行:

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保证数组中所有promise对象都达到resolve状态,才执行then回调

Promise.all并发限制

含义: 指每个时刻并发执行的promise数量是固定的,最终执行的结果还是保持与原来的promise.all一致。

思路与实现

采用递归调用来实现,设置最大请求数量上限。并在这些请求中的每一个都应该在完成时继续递归发送,通过传入的索引来确定了urls里面具体是那个URL,保证最后输出的顺序不会乱,而是依次输出

代码实现:

function multiRequest(urls = [], maxNum) {
  // 请求总数量
  const len = urls.length;
  // 根据请求数量创建一个数组来保存请求的结果
  const result = new Array(len).fill(false);
  // 当前完成的数量
  let count = 0;

  return new Promise((resolve, reject) => {
    // 请求maxNum个
    while (count < maxNum) {
      next();
    }
    function next() {
      let current = count++;
      // 处理边界条件
      if (current >= len) {
        // 请求全部完成就将promise置为成功状态, 然后将result作为promise值返回
        !result.includes(false) && resolve(result);
        return;
      }
      const url = urls[current];
      console.log(`开始 ${current}`, new Date().toLocaleString());
      fetch(url)
        .then((res) => {
          // 保存请求结果
          result[current] = res;
          console.log(`完成 ${current}`, new Date().toLocaleString());
          // 请求没有全部完成, 就递归
          if (current < len) {
            next();
          }
        })
        .catch((err) => {
          console.log(`结束 ${current}`, new Date().toLocaleString());
          result[current] = err;
          // 请求没有全部完成, 就递归
          if (current < len) {
            next();
          }
        });
    }
  });
}

代码实现:

    // 任务列表->新建任务

    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(); // 完成请求

            }

            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) => {

                  for (let i in _this.rowData) {

                    _this.rowData[i].name === item.name

                      ? (_this.rowData[i].percent = 0)

                      : "";

                  }

                  _this.$notify.error({

                    title: "错误",

                    message: "服务连接错误 " + item.name + " 未上传成功",

                  });

                })

                .finally(() => {

                  uploadThreadNums--;

                  resultFinishNum++;

                  upload();

                })

            );

          })(sendFinishNum);

          uploadThreadNums++;

          sendFinishNum++;

        }

      };

      var creatTask = function () {

        axios.all(tasks).then((res) => {

          // 新建上传任务

           /* let fd1, fd2, calcFlag, flagArr, language;

          fd1 = {};

          flagArr = Object.assign([], _this.ruleForm.checkList);

          if (_this.ruleForm.recognize == "自动识别") {

            flagArr.push("2");

          }

          calcFlag = flagArr.reduce(

            (accu, curr) => Number(accu) + Number(curr)

          );

          _this.ruleForm.recognize == "自动识别"

            ? (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 语音, 2 视频

          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();

    },

 

 

 

 

 

 

 

 

标签:function,fd1,resolve,return,请求,js,current,Ajax
来源: https://blog.csdn.net/m0_37714008/article/details/112462983