繁体   English   中英

Service Worker “获取重入”

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM