利用js实现Ajax并发请求限制请求数量的示例代码
2021-04-08 04:06
996 查看
出现问题描述:当不确定异步请求个数时,为防止当一瞬间发生上百个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并发请求限制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:相关文章推荐
- 利用js实现前后台传送Json的示例代码
- 使用$.getJSON实现跨域ajax请求示例代码
- 使用$.getJSON实现跨域ajax请求示例代码
- PHP中利用redis实现消息队列处理高并发请求--简洁代码实现效果
- 使用$.getJSON实现跨域ajax请求示例代码
- 15行代码实现一个带并发数限制的fetch请求函数
- js实现限制textarea字符输入数量的代码实例
- 利用js实现前台动态添加文本框,后台获取文本框内容(示例代码)
- js原生ajax请求代码示例
- 利用原生JS实现data方法示例代码
- java程序利用HttpSessionListener实现统计在线人数(示例代码)
- 利用JS重写Cognos右键菜单的实现代码
- Ajax 实现在WebForm中拖动控件并即时在服务端保存状态数据 (Asp.net 2.0)(示例代码下载)
- jquery 利用show和hidden实现级联菜单示例代码
- 利用script标签实现的跨域名AJAX请求(ExtJS)
- 利用JQuery jsonp实现Ajax跨域请求 .Net 的*.handler 和 WebService,返回json数据
- ASP.NET利用ajax实现弹窗报警提示,邮件到达示例
- js/ajax跨越访问-jsonp的原理和实例(javascript和jquery实现代码)
- js实现页面转发功能示例代码
- jQ/js限制textarea字符输入数量代码