- 在 Chrome 浏览器中允许的最大并发请求数目为 6,这个限制还有一个前提是针对同一域名的,超过这一限制的后续请求将会被阻塞
以下是 Chrome 浏览器关于最大请求链接数的一段介绍和相关代码,另外 Chrome 浏览器是不能修改这个值的,在源码里可以看到是固定写死的。
https://chromium.googlesource.com/chromium/src/+/65.0.3325.162/net/socket/client_socket_pool_manager.cc#44
// Default to allow up to 6 connections per host. Experiment and tuning may
// try other values (greater than 0). Too large may cause many problems, such
// as home routers blocking the connections!?!? See http://crbug.com/12066.
int g_max_sockets_per_group[] = {
6, // NORMAL_SOCKET_POOL
255 // WEBSOCKET_SOCKET_POOL
};
实现一个并发请求控制类
class RequestLimit {
constructor (limit) {
this.limit = Number(limit) || 2; // {1}
this.blockQueue = [];
this.currentReqNumber = 0;
}
/**
* 请求
* @param {*} req
*/
async request(req) { // {2}
if (!req) {
throw new Error('req is required.');
}
if (Object.prototype.toString.call(req) !== '[object Function]') {
throw new Error('Req must be a function.');
}
if (this.currentReqNumber >= this.limit) { // {3}
await new Promise(resolve => this.blockQueue.push(resolve)); // 阻塞队列增加一个 Pending 状态的 Promise
}
return this._handlerReq(req); // {4}
}
/**
* 内部方法处理请求
* @param {*} req
*/
async _handlerReq(req) {
this.currentReqNumber++; // {5}
try {
return await req();
} catch (err) {
return Promise.reject(err);
} finally {
this.currentReqNumber--;
if (this.blockQueue.length) { // 每完成一个就从阻塞队列里剔除一个
this.blockQueue[0](); // 将最先进入阻塞队列的 Promise 从 Pending 变为 Fulfilled
this.blockQueue.shift();
}
}
}
}
上述代码有一个重点是 this.block() 函数如何实现阻塞,这一块可以借助 Promise 实现,在 new Promise 时回调函数会给我们返回一个 resolve 函数,如果执行这个 resolve 函数,Promise 的状态会变更为 Fulfilled 所以我们这里不会立即执行,而是先保存到阻塞队列里,待前面的请求完成之后再从阻塞队列里取出,相当于执行了 resolve 函数,如果理解 Promise 源码实现的会好理解些。