代码片段之js限流调度器
以下保证都是我自己手敲出来的, 所以保证了原创性, 保证不了正确性.
概念
限流调度器, 本意是指对 js 的任务进行限流(同时不要做多个
), 在我理解 js 中对任务限流其实主要就是对js
的http
请求进行限流, 因为其他任务需要限流的场景我还没有遇到过(这种场景是肯定有的, 有遇到的欢迎和我互动啊~~
). 为什么需要对http
请求进行限流呢? 因为各种环境对http
请求都有限制
网络速度有限制(网络没有那么快)
服务器响应的速度有限制(服务器没有那么快)
浏览器对
http
请求有限制同时请求数量有限制
等待队列的请求数量有限制
下面写了个小例子, 验证第三点
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <script> for (let i = 0; i < 2000; i++) { fetch(`http://127.0.0.1:3000/get?index=${i}`) } </script> </body> </html> 复制代码
const express = require('express') const app = express() const sleep = async (time) => { return new Promise((res) => { setTimeout(res, time) }) } app.get('/get', async (req, res) => { await sleep(10000) res.end('') }) app.listen(3000, () => { console.log('启动了') }) 复制代码
第二种情况(同时发大量请求, 一千多个
)几乎不会出现, 所以针对第一种情况(浏览器同时只发送 6 个请求
)需要对一些不重要的请求(比如预加载一百张图片
)进行限流, 防止阻塞重要的请求(比如用户签到
).
实现
思路
肯定得有一个缓存器, 把那些还没有发送的请求存起来
肯定有个上限, 这个上限肯定比 6 小, 当正在请求数大于这个数时, 不再请求
代码
这里没有处理边界情况, 也没有处理报错, 只是简单的代码实现
class LimitRequest { // 限制同时请求的数量 limitCount = 0 // 缓存还没有发送的请求 cacheRequest = [] // 当前正在请求的数量 currentRequest = 0 constructor(limitCount) { this.limitCount = limitCount } /** * 新增请求 * @param {*} fn */ addRequest(fn) { // 把这个请求缓存起来 this.cacheRequest.push(fn) // 发送请求 // 这个发送请求可以不写, 由用户自己手动去调用 this.request() } /** * 从缓存中拿出一条请求, 发送 */ async request() { if (this.currentRequest >= this.limitCount) { // 如果当前请求数量超出了限制, 不再发送新的请求 return } // 当前正在请求的数量加一 this.currentRequest++ // 拿出缓存的请求 const fn = this.cacheRequest.shift() // 发送请求 await fn() // 请求结束, 当前正在发送的请求减一 this.currentRequest-- // 空出一个名额, 可以再次请求 this.request() } } 复制代码
完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <script> class LimitRequest { // 限制同时请求的数量 limitCount = 0 // 缓存还没有发送的请求 cacheRequest = [] // 当前正在请求的数量 currentRequest = 0 constructor(limitCount) { this.limitCount = +limitCount || 3 } /** * 新增请求 * @param {*} fn */ addRequest(fn) { if (typeof fn !== 'function') { console.log('addRequest添加请求需要传入函数') return } // 把这个请求缓存起来 this.cacheRequest.push(fn) // 修改, 这里不去调用了, 留着用户自己在合适的时机调用 } /** * 从缓存中拿出一条请求, 发送 */ async request() { if (this.currentRequest >= this.limitCount) { // 如果当前请求数量超出了限制, 不再发送新的请求 return } // 当前正在请求的数量加一 this.currentRequest++ // 这里是用户主动调的, 所以一次要请求到上限 this.request() try { // 拿出缓存的请求 const fn = this.cacheRequest.shift() // 发送请求 await fn() } catch (err) { console.log('执行fn报错', err) } finally { // 请求结束, 当前正在发送的请求减一 this.currentRequest-- if (this.cacheRequest.length) { // 空出一个名额, 并且还有请求, 可以再次请求 this.request() } } } } const limitRequest = new LimitRequest(3) for (let i = 0; i < 2000; i++) { limitRequest.addRequest(async () => { await fetch(`http://127.0.0.1:3000/get?index=${i}`) }) } setTimeout(() => { // 在3秒之后, 浏览器空闲了, 发送请求 limitRequest.request() }, 3000) </script> </body> </html> 复制代码
最后
欢迎互动 欢迎加我微信呀~~~~
作者:__冬冬来了__
链接:https://juejin.cn/post/7015257618088198180