出现问题描述:当不确定异步请求个数时,为防止当一瞬间发生上百个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并发请求限制内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论