httpRequest(url, options)
这个函数来发实际的网络请求function httpRequest(url, options){
// 真实的网络请求省略
return new Promise((resolve, reject) => {
// xxx
});
}
class NetManager {
constructor(concurrency) {
}
request(url, data) {
}
}
class
,内部会有网络请求的并发限制,如果达到限制,则内部维持队列处理NetManager
的 request
方法时,不考虑是否达到了并发限制。也就是说,并发限制对调用方是透明 的,简单说,就是不管是否达到了并发限制, request
方法始终返回的是一个 Promise
class NetManager {
constructor(concurrency) {
// 保存并发数
this.concurrency = concurrency;
// 待处理队列
this.queue = [];
}
request(url, data) {
return new Promise((resolve, reject) => {
httpRequest(url, data).then(resolve, reject);
});
}
}
request
的函数实现,能满足对外使用(不管是否超出并发数)始终不变,接下来增加并发限制。class NetManager {
constructor(concurrency) {
// 保存并发数
this.concurrency = concurrency;
// 待处理队列
this.queue = [];
// 处理中的个数
this.processCount = 0;
}
request(url, data) {
return new Promise((resolve, reject) => {
// 这里不再直接发请求,而是放到队列里
// 这里把这个 promise 的 resolve/reject 先和请求参数一起放到队列里,
// 等待实际请求之后再改变promise状态,把最终数据(异常)返回给调用方
this.queue.push({
url,
data,
resolve,
reject,
});
// 尝试处理第一个任务
this._processNext();
});
}
// 内部私有函数,判断当前是否超过并发数,未超过就从队列取出第1个发送请求
_processNext() {
if (this.processCount >= this.concurrency) {
// 超过并发数,啥都不做
return;
}
const obj = this.queue.shift();
if (obj) {
// 有待处理任务,取出来发送
this.processCount++;
const p = httpRequest(obj.url, obj.data);
p.finally((res) => {
// 网络请求完成,不管成功还是失败,都将进行中减1
this.processCount--;
// 尝试处理下一个任务
this._processNext();
});
// 把实际的网络返回数据(失败错误)传给调用方
p.then(obj.resolve, obj.reject);
}
}
}
NetManager
类。其实这个题目也不是空想出来的,毕竟在浏览器内部,本身就对单个域名的并发数有限制,有时在一些性能优化的场景下,我们也需要手动控制网络的顺序、优先级,或者并发数,希望通过这道题目,能给大家一些基本的思路。“前端面试题宝典”经历接近一年的迭代打磨,目前已经提供了小程序刷题、PC端访问(https://fe.ecool.fun/)。
截至2022年3月31日,已经录入前端常见面试题800+,想刷前端面试题的小伙伴千万不要错过。
我们在近期推出了简历指导、模拟面试等增值服务,有想了解的小伙伴们可以添加小助手微信(interview-fe)进行咨询哦~