浏览器同域名下对并发请求的数量是有限制的,通常是 4 ~ 8
以内。超出的会被置入队列等待发送,即 待处理 pending
状态
如果并发请求量达到一定量级的时候,堆积了无数的调用栈就有可能会导致 内存溢出
浏览器的并发限制
-
Chrome 浏览器
同一域名同时最多只能建立
6
个TCP
连接,也就是说单个域名最大的并发量不超过6
个 -
Safari 浏览器
同一域名同时最多只能建立
4
个TCP
连接,也就是说单个域名最大的并发量不超过4
个
协议的并发限制(HTTP1.1)
-
持续连接
支持
TCP
连接的复用,持续连接在默认情况下是激活的,可以被多个请求复用且不需要声明
Connection: keep-alive
-
管线化
对
HTTP
请求每次只能是请求一次响应一次的模式进行改进允许在第一个响应被完全发送之前就可以发送第二个请求(可以一次性发送多个请求),以降低通信延迟
-
队头堵塞
在接收响应报文时,必须依赖请求顺序接收。如果前一个请求遇到了阻塞,后面的请求即使已经处理完了,仍然需要等待阻塞的请求处理完成
场景示例
-
业务场景
假设现在有
1000
个异步任务需要执行,但出于性能的考虑,我们必须将执行的数量控制在3
个以内,同时还要尽可能快的拿到响应结果如:大文件的批量上传、大量的图片加载等 量化异步任务的执行且影响性能 的场景
-
生活示例
排队购票和异步任务并发的场景类似,只有三台售票机,当购票人数超过三个后,就需要依次进行排队等候
优化方案
-
参数注解
/** * @description 异步任务并发量的控制 * @param {Array} list 迭代数组 * @param {Number} limit 控制的并发数量 * @param {Function} handler 对list每一项的处理函数 */ 复制代码
-
首先,通过 while 循环实现初始并发
while(limit--) { handler(list.shift()) } 复制代码
-
然后,通过递归依次执行下一个,直到全部执行完
const runInSequence = async (list, handler, callback) => { const item = list.shift() if (item) { const result = await handler(item) callback(result) list.length && runInSequence(list, handler, callback) } } 复制代码
-
最后,组合以上逻辑
const asyncThrottling = ({ list, limit = 3, handler = () => {} }) => { const response = [], len = list.length return new Promise(resolve => { limit = len > limit ? limit : len while(limit--) { runInSequence(list, handler, result => { response.push(result) response.length === len && resolve(response) }) } }) } 复制代码
-
一起交流学习
加群交流看沸点