[英]Service Worker “fetch reentrancy”
我正在使用服务人员缓存通过 rest 服务发出的请求。 该实现对应于本页https://web.dev/offline-cookbook/中描述的“网络响应”。
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open('mysite-dynamic').then(function (cache) {
return cache.match(event.request).then(function (response) {
return (
response ||
fetch(event.request).then(function (response) {
cache.put(event.request, response.clone());
return response;
})
);
});
}),
);
});
这个想法是:
1. caller makes 1st request A
2. service worker intercepts the request A
3. service worker checks whether a request A is in storage -> no
4. service worker sends the request A to the rest service
5. service worker gets the response A
6. service worker stores the response A
7. service worker returns the response A to the caller
...
8. caller makes 2nd request A
9. service worker intercepts the request A
10. service worker checks whether a request A is in the cache -> yes
11. service worker gets the response A from storage
12. service worker returns the response A to the caller
问题是 rest 请求需要一些时间才能返回响应,并且可能会出现向 rest 服务发出 2 个或更多请求的情况:
1. caller makes 1st request A
2. service worker intercepts the request A
3. service worker checks whether a request A is in storage -> no
4. service worker sends the request A to the rest service
5. caller makes 2nd request A
6. service worker intercepts the request A
7. service worker checks whether a request A is in storage -> no
8. service worker gets the response A
9. service worker stores the response A
10. service worker returns the response A to the caller
11. service worker gets the response A
12. service worker stores the response A
13. service worker returns the response A to the caller
如何只发送 1 个请求?
如果你愿意使用 Workbox 库,而不是“vanilla”服务工作者代码, 这个秘籍可能会有所帮助:
// See https://developers.google.com/web/tools/workbox/guides/using-bundlers
import {NetworkFirst} from 'workbox-strategies';
class DedupeNetworkFirst extends NetworkFirst {
constructor(options) {
super(options);
// This maps inflight requests to response promises.
this._requests = new Map();
}
// _handle is the standard entry point for our logic.
async _handle(request, handler) {
let responsePromise = this._requests.get(request.url);
if (responsePromise) {
// If there's already an inflight request, return a copy
// of the eventual response.
const response = await responsePromise;
return response.clone();
} else {
// If there isn't already an inflight request, then use
// the _handle() method of NetworkFirst to kick one off.
responsePromise = super._handle(request, handler);
this._requests.set(request.url, responsePromise);
try {
const response = await responsePromise;
return response.clone();
} finally {
// Make sure to clean up after a batch of inflight
// requests are fulfilled!
this._requests.delete(request.url);
}
}
}
}
然后,您可以将DedupeNetworkFirst
class 与Workbox 的 router一起使用,或者,如果您不想使用更多 Workbox,则可以直接在您自己的fetch
处理程序中使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.