【高级】最大并发请求控制
实现一个createRequest方法(假设浏览器允许无限多的并行请求)实现最大并发请求量控制。调用形式如下图,最后实现效果如图:
其中request函数的输入输出和fetch函数保持一致
参考答案:
function createRequest({ pool = 6 }) {
const requestingArray = []; // 请求队列
const pendingArray = []; // 等待队列
/**
* 每个请求完成后,检查是否存在等待的请求
*/
function checkPending() {
if (pendingArray.length && requestingArray.length <= pool) {
const promiseObject = pendingArray.shift();
requestingArray.push(promiseObject);
// resolve 等待的请求,触发其调用 wrappedFetch
promiseObject.resolve();
}
}
/**
* 封装 fetch 方法,在请求完成后将该请求从 requestingArray 移除,并检查等待队列
*/
function wrappedFetch({ url, options, promiseObject }) {
return new Promise((resolve, reject) => {
fetch(url, options)
.then((data) => {
resolve(data);
})
.catch((err) => {
reject(err);
})
.finally(() => {
// 将 promiseObject 从 requestingArray 移除
const index = requestingArray.indexOf(promiseObject);
if (index >= 0) {
requestingArray.splice(index, 1);
}
checkPending();
});
});
}
return (url, options) => {
const promiseObject = {};
// 存储 resolve 方法,在上一个请求结束后调用
const promise = new Promise((resolve) => {
promiseObject.resolve = resolve;
});
// 方式一:判断新的请求能否直接发起请求
if (requestingArray.length >= pool) {
// 等待
pendingArray.push(promiseObject);
} else {
// 发起请求
requestingArray.push(promiseObject);
promiseObject.resolve();
}
// 方式二:也可以直接将所有请求放入等待队列,再检查是否可以请求
// pendingArray.push(promiseObject);
// checkPending();
return promise.then(() =>
wrappedFetch({
url,
options,
promiseObject,
})
);
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69