原理
- 监听
fetch
事件,在事件处理函数中判断当前并发数是否超过限制。 - 如果超过限制,将请求加入队列,等待其他请求完成。
- 如果没有超过限制,直接发送请求。
实现
在 index.html 中注册 Service Worker
html
<!DOCTYPE html>
<html lang="zh_CN">
<body>
<div id="app"></div>
<script>
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("/sw.js", {
scope: "/",
});
});
}
</script>
<script type="module" src="./src/main.ts"></script>
</body>
</html>
添加 sw.js
js
// 最大并发数
const MAX_CONCURRENT = 8;
let activeCount = 0;
const requestQueue = [];
self.skipWaiting();
self.addEventListener("fetch", (event) => {
// 对部分接口进行限制并发数,其他请求直接放行,例如对包含 xxx.api. 的接口限制并发数
if (!["xxx.api."].some((item) => event.request.url.includes(item))) {
return;
}
// 克隆请求对象,因为请求体只能读取一次
const request = event.request.clone();
// 将请求加入队列
const promise = new Promise((resolve, reject) => {
requestQueue.push({ request, resolve, reject });
processQueue();
});
event.respondWith(promise);
});
function processQueue() {
// 队列为空或已达到最大并发数则不处理
if (requestQueue.length === 0 || activeCount >= MAX_CONCURRENT) {
return;
}
// 从队列中取出下一个请求
const { request, resolve, reject } = requestQueue.shift();
activeCount++;
// 处理请求
fetch(request)
.then((response) => {
resolve(response);
})
.catch((error) => {
reject(error);
})
.finally(() => {
activeCount--;
processQueue(); // 处理下一个请求
});
}
检查 Service Worker 是否生效
接口前有特殊图标或者实际的请求接口有 from service worker 表示成功。
在 Application 中也能查看对应的 Service Worker 是否注册成功