版本一:
const pipRequest = (idsarr, callback) => {
const start = Date.now();
const len = idsarr.length;
const result = []; // 结果集
const ajaxMax = 3; // 最多允许同时执行的ajax次数
let ajaxNum = 0; // 当前有多少ajax正在执行
const ajax = (id) => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${id}的结果`);
}, 500);
})
const main = (ids) => {
console.log(`时间:${Date.now() - start}`);
while (ajaxNum <= ajaxMax && ids.length > 0) { // 只要有位置就发请求
ajaxNum++;
const now = ids.shift() // 发了一个请求
ajax(now).then(res => {
result.push(res);
main(ids);
}).catch((_) => {
ids.push(now); // 失败的请求重新加入队列
}).finally(() => {
ajaxNum--;
(
result.length === len
&& typeof callback === 'function'
&& callback(result)
);
})
}
}
main(idsarr);
}
pipRequest([...Array(100).keys()], function (res) {
console.log(res);
})
版本二:
这个版本比较好理解,但是实现私有属性的#方法兼容性很差。
const ajax = (id) => new Promise((resolve, reject) => setTimeout(() => {
resolve(`${id}结果`);
}, 500))
class Request {
// 初始化数据
constructor(arr = [], callback) {
this.arr = arr;
this.callback = this.#checkCallBackLegal(callback) && callback;
}
#result = [];
#curIndex = 0;
#maxNum = 3;
#pool = new Set();
// 启动函数,从arr的第0项开始启动
async start() {
await this.#addPool();
}
// 加入池子,如果池中满了或者超出则不放置
#addPool = ()=>{
if (this.#pool.size < this.#maxNum && this.arr.length > this.#curIndex) {
const id = this.#send();
this.#pool.add(id);
this.#curIndex++;
this.#addPool();
}
}
// 移出池子
#removePool = (id)=>{
this.#pool.delete(id)
}
// 返回ajax,单个请求
#send = ()=>{
const id = this.#curIndex;
ajax(this.arr[id]).then((res) => {
this.#log(res);
this.#result.push(res);
}).then(res => {
this.#removePool(id);
this.#addPool();
this.#doCallBack()
});
return id;
}
#log = (res)=>{
console.log(`${res} has been resolved`);
}
#checkCallBackLegal = (callback)=>{
return (callback && typeof callback === 'function');
}
#doCallBack = ()=>{
if (this.arr.length === this.#result.length) {
this.callback(this.#result);
}
}
}
const arr = [...Array(100).keys()];
new Request(arr, (res) => {
console.log(res);
}).start();
版本三:
这个版本的私有成员兼容性比较好,但是这TM也太难看了,突然想说java真香,JavaScript就是个垃圾。
// 函数闭包化
const closure = (func) => {
return (func)();
}
// ajax
const ajax = (id) => new Promise((resolve, reject) => setTimeout(() => {
resolve(`${id}结果`);
}, 500))
var Request =() => {
// 实现私有属性
const result = Symbol();
const curIndex = Symbol();
const maxNum = Symbol();
const pool = Symbol();
const addPool = Symbol();
const removePool = Symbol();
const send = Symbol();
const log = Symbol();
const checkCallBackLegal = Symbol();
const doCallBack = Symbol();
class Request {
constructor(arr = [], callback) {
// 初始化数据
this.arr = arr;
this.callback = this[checkCallBackLegal](callback) && callback;
// 初始化私有属性
this[result] = [];
this[curIndex] = 0;
this[maxNum] = 3;
this[pool] = new Set();
}
// 启动函数,从arr的第0项开始启动
async start() {
await this[addPool]();
}
// 加入池子,如果池中满了或者超出则不放置
[addPool]() {
if (this[pool].size < this[maxNum] && this.arr.length > this[curIndex]) {
this[send]();
this[pool].add(this[curIndex]);
this[curIndex]++;
this[addPool]();
}
}
// 移出池子
[removePool](id) {
this[pool].delete(id)
}
// 返回ajax,单个请求
[send]() {
const id = this[curIndex];
ajax(this.arr[id]).then((res) => {
this[log](res);
this[result].push(res);
}).then((_) => {
this[removePool](id);
this[addPool]();
this[doCallBack]();
});
}
// 打印日志
[log](res) {
console.log(`${res} has been resolved`);
}
// 检查回调函数是否合法
[checkCallBackLegal](callback) {
return (callback && typeof callback === 'function');
}
// 执行回调函数
[doCallBack]() {
// 执行回调函数的时机判断,
if (this.arr.length === this[result].length) {
this.callback(this[result]);
}
}
}
return Request;
}
var RequestClosure = closure(Request);
const arr = [...Array(100).keys()];
new RequestClosure(arr, (res) => {
console.log(res);
}).start();
const start = Date.now();
const ajax = () => new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, 500);
});
function multiRequest(urls = [], maxNum) {
// 请求总数量
const len = urls.length;
// 根据请求数量创建一个数组来保存请求的结果
const result = new Array(len).fill(false);
// 当前完成的数量
let count = 0;
return new Promise(resolve => {
while (count < maxNum) {
next();
}
const save = (res, current) => {
result[current] = res;
console.log(res,Date.now() - start);
if (current < len) {
next();
}
}
function next() {
let current = count++;
if (current >= len) {
result.every(Boolean) && resolve(result);
return;
}
ajax(urls[current])
.then((res) => save(res, current))
.catch((res) => save(res, current))
}
});
}
multiRequest([...Array(100).keys()],3)