MCPcopy
hub / github.com/angular/angular / fetchAndCacheOnce

Function fetchAndCacheOnce

packages/service-worker/worker/src/assets.ts:300–364  ·  view source on GitHub ↗

* Fetch the given resource from the network, and cache it if able.

(req: Request, used: boolean = true)

Source from the content-addressed store, hash-verified

298 * Fetch the given resource from the network, and cache it if able.
299 */
300 protected async fetchAndCacheOnce(req: Request, used: boolean = true): Promise<Response> {
301 // The `inFlightRequests` map holds information about which caching operations are currently
302 // underway for known resources. If this request appears there, another "thread" is already
303 // in the process of caching it, and this work should not be duplicated.
304 if (this.inFlightRequests.has(req.url)) {
305 // There is a caching operation already in progress for this request. Wait for it to
306 // complete, and hopefully it will have yielded a useful response.
307 return this.inFlightRequests.get(req.url)!;
308 }
309
310 // No other caching operation is being attempted for this resource, so it will be owned here.
311 // Go to the network and get the correct version.
312 const fetchOp = this.fetchFromNetwork(req);
313
314 // Save this operation in `inFlightRequests` so any other "thread" attempting to cache it
315 // will block on this chain instead of duplicating effort.
316 this.inFlightRequests.set(req.url, fetchOp);
317
318 // Make sure this attempt is cleaned up properly on failure.
319 try {
320 // Wait for a response. If this fails, the request will remain in `inFlightRequests`
321 // indefinitely.
322 const res = await fetchOp;
323
324 // It's very important that only successful responses are cached. Unsuccessful responses
325 // should never be cached as this can completely break applications.
326 if (!res.ok) {
327 throw new Error(
328 `Response not Ok (fetchAndCacheOnce): request for ${req.url} returned response ${res.status} ${res.statusText}`,
329 );
330 }
331
332 try {
333 // This response is safe to cache (as long as it's cloned). Wait until the cache operation
334 // is complete.
335 const cache = await this.cache;
336 await cache.put(req, res.clone());
337
338 // If the request is not hashed, update its metadata, especially the timestamp. This is
339 // needed for future determination of whether this cached response is stale or not.
340 if (!this.hashes.has(this.adapter.normalizeUrl(req.url))) {
341 // Metadata is tracked for requests that are unhashed.
342 const meta: UrlMetadata = {ts: this.adapter.time, used};
343 const metaTable = await this.metadata;
344 await metaTable.write(req.url, meta);
345 }
346
347 return res;
348 } catch (err) {
349 // Among other cases, this can happen when the user clears all data through the DevTools,
350 // but the SW is still running and serving another tab. In that case, trying to write to the
351 // caches throws an `Entry was not found` error.
352 // If this happens the SW can no longer work correctly. This situation is unrecoverable.
353 throw new SwCriticalError(
354 `Failed to update the caches for request to '${
355 req.url
356 }' (fetchAndCacheOnce): ${errorToString(err)}`,
357 );

Callers

nothing calls this directly

Calls 9

errorToStringFunction · 0.90
normalizeUrlMethod · 0.80
hasMethod · 0.65
getMethod · 0.65
setMethod · 0.65
putMethod · 0.65
cloneMethod · 0.65
writeMethod · 0.65
deleteMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…