利用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) => {
           ? (_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();
  },

到此这篇关于利用js实现Ajax并发请求限制请求数量的示例代码的文章就介绍到这了,更多相关js Ajax并发请求限制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 字节跳动面试之如何用JS实现Ajax并发请求控制

    前言 讲真的,最近也很迷茫.关于技术.关于生活吧.也找了很多在大厂的朋友去聊,想需求一些后期发展的思路.这其中也聊到了面试,聊到了招聘中会给面试者出的一些题目.我正好也好久没面试了,就从中选了几道.最近也会陆续出一系列关于一些面试问题的解析. 今天这道是字节跳动的: 实现一个批量请求函数 multiRequest(urls, maxNum),要求如下: • 要求最大并发数 maxNum • 每当有一个请求返回,就留下一个空位,可以增加新的请求 • 所有请求完成后,结果按照 urls 里面的顺序依

  • 利用js实现Ajax并发请求限制请求数量的示例代码

    出现问题描述:当不确定异步请求个数时,为防止当一瞬间发生上百个http请求时,导致堆积了无数调用栈进而导致内存溢出问题. 要求:将同一时刻并发请求数量控制在3个以内,同时还要尽可能快速的拿到响应的结果. 同面试问题: 实现一个批量请求函数 multiRequest(urls, maxNum),要求如下: 要求最大并发数 maxNum 每当有一个请求返回,就留下一个空位,可以增加新的请求 所有请求完成后,结果按照 urls 里面的顺序依次打出 1.基于Promise.all实现Ajax的串行和并行

  • 如何基于JS实现Ajax并发请求的控制详解

    目录 前言 Ajax的串行与并行 Ajax的并发请求控制的两大解决方案 基于Promise递归实现 基于Class实现 代码展示 总结 前言 最近看到一个面试题,当然了,就是这篇文章的标题,Ajax的并发请求的控制,感觉挺有意思的,在社区看了下,应该是字节的面试题,也挺多大佬对这个进行了总结,都看了下,于是自己也想试着总结下,代码文末会全部贴出,如有不足,请指出! Ajax的串行与并行 串行:一般业务需求是下个接口需要用到上个接口的返回的数据,前端常用的请求库是Axios,本身就是基于Promi

  • 利用js将ajax获取到的后台数据动态加载至网页中的方法

    动态生成二级菜单树: <script> jQuery(function($) { /********** 获取未处理报警信息总数 **************/ var result; $.ajax({ async:false, cache:false, url: "alarm_findPageAlarm.do",//访问后台接口取数据 // dataType : "json", type: 'POST', success: function(data)

  • Java中利用Alibaba开源技术EasyExcel来操作Excel表的示例代码

    一.读Excel 1.Excel表格示例 2.对象示例 @Data public class DemoData { private String string; private Date date; private Double doubleData; } 3.监听器(重点部分) // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 public class DemoDataListener e

  • Echarts利用多X轴实现七天天气预报效果的示例代码

    目录 UI设计图 Echarts示例效果 前言 示例代码 最终效果 UI设计图 Echarts示例效果 前言 对于UI给出的设计图,各个气象网站都有类似的效果,实现方式大可归为两种: 网格布局+图表框架绘制温度曲线: 网格布局+canvas自绘温度曲线: 这两种实现方式的共同点都是将曲线和上面的描述文字拆分开来,这样做难点是要实现日期图标部分和气温曲线部分的自适应对齐.因为我CSS经验相对比较薄弱,并且使用Echarts图表框架相对较多,所以决定尝试使用Echarts(版本:4.6.0)来实现上

  • Java利用TCP实现服务端向客户端消息群发的示例代码

    目录 前言 代码 tcp服务端代码 ServerThread 线程类 TcpTool 消息群发工具类 Tcp客户端代码 前言 项目需要和第三方厂商的服务需要用TCP协议通讯,考虑到彼此双方可能都会有断网重连.宕机重启的情况,需要保证 发生上述情况后,服务之间能够自动实现重新通信.研究测试之后整理如下代码实现.因为发现客户端重启后,对于服务端来说原来的客户端和服务端进程进程已经关闭,启动又和服务端新开了一个进程.所以实现原理就可以通过服务端向客户端群发实现,断开重新连接通讯. 代码 tcp服务端代

  • js带按钮的提示框可供选择示例代码

    今天在项目当中遇到一个问题(本人前台功底不深,高手勿喷): 可以供选择的弹出框: 利用jQuery没有想到好的提示效果. 参看js的API文档实现如下===confirm: 复制代码 代码如下: var r=confirm("该订单号已经存在,请重新输入或查询已存在订单详情!") if (di != null&& (r==true)) { userNameCnl.focus();//定位 userNameCnl.value = "";//清空数据 }

  • C#网络请求与JSON解析的示例代码

    最新学校的海康摄像头集控平台(网页端)不能在win10里登录,我寻思着拿海康的c# demo直接改. 首先得解决权限问题,每个教师任教不同年级,只能看到自己所在年级的设备,涉及到登录,在此记录一下C#中网络请求和数据处理的一些内容.大致流程为: 客户端发起登录请求: 服务端验证账号密码 返回json字符串,包含用户信息.平台配置等信息 客户端解析并初始化 一.发起GET请求 private string HttpGet(string api) { string serviceAddress =

  • Nuxt.js实现一个SSR的前端博客的示例代码

    为什么要用Nuxt.js 公司现有的项目只有落地页是通过前端本身server读取pug文件进行服务端渲染的,当然是为了首屏加载速度以及SEO.Nuxt.js 是一个基于Vue.js的通用应用框架,预设了利用Vue.js开发服务端渲染的应用所需要的各种配置,只需要安装官方文档的要求进行开发,就可以很好的解决SSR的问题.我们以一个简单的博客为例,来实践一下Nuxt.js. 项目介绍 当前基于Nuxt.js的简化版博客,包括注册.登录.文章列表页面.文章详情页.以及用户列表页等几个页面,用户信息使用

随机推荐