前端请求并发控制
介绍
在列表的导入导出时如果后台接口不支持多条传入并且后台控制了TPS(吞吐量)时可以使用这种方法
主要思想:
前端在请求数据时,先将所有的请求保存下来,在规定的并发内进行一个个的请求
包工头李四有20个搬砖工人,有一天,他有一大车的砖要搬,就把这些人叫来,动员大家搬砖,工人们一个个的干劲很高,一个个的在门口等着搬砖,早晨的砖不是那么烫手,车来了,大家开始搬砖。
问题出现了,门太小,一时间只能进去俩人,并且要等俩人出来才能让后面两个人进去,这样严重拖慢了赚钱速度,但是也不能直接把门给拆了,所以机灵的李四就让另外的18个人去张三的工地搬砖,那里的门大,砖多,这里就留两个搬就能完美的配合这个门
// 记录当前请求的次数
var count = 1;
// websocket请求连接
var connect = ()=> {
return new Promise((resolve,reject)=>{
let kstime = ""; // 开始时间
let ljtime = ""; // 连接时间
let fhtime = ""; // 返回时间
// 连接本机
let ws = new WebSocket("ws://192.168.8.216:8996");
ws.onmessage = function (message) {
fhtime = new Date().getTime();
console.log("发送返回耗时:", fhtime - ljtime);
console.log("总耗时:", fhtime - kstime);
ws.close();
console.log(message)
resolve(message)
};
ws.onopen = function (time) {
// 状态为1表示连接成功
console.log("第" + count + "次");
count++;
console.log("正在连接中:");
if (ws.readyState === 1) {
ljtime = new Date().getTime();
console.log("连接消耗时间:", ljtime - kstime);
ws.send(count);
}
};
ws.onclose = function (ms) {
console.log(kstime, "开始创建");
console.log(ljtime, "连接上");
console.log(fhtime, "返回回来");
console.log("-------------------------------------------------");
};
kstime = new Date().getTime();
})
};
// 传入一个数字控制当前同时请求条数,只有在请求返回之后才能再次请求 验证数字
function validateCore(core) {
if (core < 1) {
throw new Error('parameter `core` must great than 0')
}
}
class PromisePool {
constructor(core) {
validateCore(core)
this.core = core
this.isPause = false
}
core = 2 // 来几个人搬砖
taskQueue = [] // 还有那么多砖要搬
status = false // 是否正在搬砖
isPause = false // 正在休息码
// Promise状态
statusPromise(){
return Promise.resolve()
}
// 获取promise状态
getStatusPromise() {
return this.statusPromise
}
// 添加砖
execute(feature) {
this.taskQueue.push(feature)
return this.resume()
}
// 砖拉走了
async clear() {
await this.pause()
this.taskQueue.splice(0, this.taskQueue.length)
return this.statusPromise
}
// 停下来吃顿午饭再说
pause() {
this.isPause = true
return this.statusPromise
}
// 干活了
resume() {
this.isPause = false
return this.beginExecute()
}
// 派多少人搬砖
async setCore(core) {
// 不能来砖了,没人搬
validateCore(core)
if (this.status) {
// 来新人了,先停一下,让新人加入荣华富贵大家庭
await this.pause()
this.core = core
// 大家一起搬砖喽
return this.resume()
} else {
this.core = core
}
}
// 大家在搬砖吗
getstatus() {
return this.status
}
// 开始搬砖
beginExecute() {
if (this.status) {
// 都已经搬砖了,继续就好了
return
}
// 干活了(萌道)
this.status = true
const promiseArray = []
for (let i = 0; i < this.core; i++) {
// 把需要砖都排好,来搬就行了
promiseArray.push(this.doExecute())
}
// 奥里给
this.statusPromise = Promise.all(promiseArray).finally(() => {
this.status = false
})
return this.statusPromise
}
// 把砖一块块的放好
doExecute(){
return new Promise(resolve => {
// 取出第一块砖放好
const executor = this.taskQueue.shift()
// 拿到砖了,就搬过去
if (executor) {
let executorPromise
if (typeof executor === 'function') {
// 是函数就执行一下
executorPromise = Promise.resolve(executor())
} else {
// 不是函数就过,只有一个工人的时候可以按照顺序,让一个人慢慢搬砖
executorPromise = Promise.resolve(executor)
}
executorPromise.finally(() => {
resolve()
})
} else {
resolve()
}
}).then(() => {
if (this.isPause) {
// 通知回来搬砖的人,可以先休息一下
return
}
// 后面还有砖,大家加油啊
if (this.taskQueue.length > 0) {
return this.doExecute()
}
})
}
}
let promisePool = new PromisePool(2)
for(let i = 0;i<10;i++){
promisePool.execute(async ()=>{
const data = await connect()
console.log(i,data)
return data
})
}
setTimeout(()=>{
promisePool.pause()
console.log(promisePool)
},5000)
砖厂收到通知,用户想要定制一批砖,意见达成,双方慢慢聊(后台处理)
// 导入WebSocket 模块
const WebSocket = require("ws");
// 引用Server 类
const WebSocketServer = WebSocket.Server;
// 实例化
const ws = new WebSocketServer({port:8996});
ws.on('connection', function (ws) {
console.log(`[SERVER] connection()`);
ws.on('message', function (message) {
console.log(`[SERVER] Received: ${message}`);
var index = 0;
var timer = setInterval(()=>{
index++;
if(index==3){
clearInterval(timer);
}
if(ws.readyState === 3){ // 断开连接
return;
}
ws.send(`ECHO: ${message},${JSON.stringify(ws)}`, (err) => {
if (err) {
console.log(`[SERVER] error: ${err}`);
}
});
},2000);
})
});