source: frontend/node_modules/workbox-strategies/NetworkFirst.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 Copyright 2018 Google LLC
3
4 Use of this source code is governed by an MIT-style
5 license that can be found in the LICENSE file or at
6 https://opensource.org/licenses/MIT.
7*/
8import { assert } from 'workbox-core/_private/assert.js';
9import { logger } from 'workbox-core/_private/logger.js';
10import { WorkboxError } from 'workbox-core/_private/WorkboxError.js';
11import { cacheOkAndOpaquePlugin } from './plugins/cacheOkAndOpaquePlugin.js';
12import { Strategy } from './Strategy.js';
13import { messages } from './utils/messages.js';
14import './_version.js';
15/**
16 * An implementation of a
17 * [network first](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#network-first-falling-back-to-cache)
18 * request strategy.
19 *
20 * By default, this strategy will cache responses with a 200 status code as
21 * well as [opaque responses](https://developer.chrome.com/docs/workbox/caching-resources-during-runtime/#opaque-responses).
22 * Opaque responses are are cross-origin requests where the response doesn't
23 * support [CORS](https://enable-cors.org/).
24 *
25 * If the network request fails, and there is no cache match, this will throw
26 * a `WorkboxError` exception.
27 *
28 * @extends workbox-strategies.Strategy
29 * @memberof workbox-strategies
30 */
31class NetworkFirst extends Strategy {
32 /**
33 * @param {Object} [options]
34 * @param {string} [options.cacheName] Cache name to store and retrieve
35 * requests. Defaults to cache names provided by
36 * {@link workbox-core.cacheNames}.
37 * @param {Array<Object>} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
38 * to use in conjunction with this caching strategy.
39 * @param {Object} [options.fetchOptions] Values passed along to the
40 * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
41 * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796)
42 * `fetch()` requests made by this strategy.
43 * @param {Object} [options.matchOptions] [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
44 * @param {number} [options.networkTimeoutSeconds] If set, any network requests
45 * that fail to respond within the timeout will fallback to the cache.
46 *
47 * This option can be used to combat
48 * "[lie-fi]{@link https://developers.google.com/web/fundamentals/performance/poor-connectivity/#lie-fi}"
49 * scenarios.
50 */
51 constructor(options = {}) {
52 super(options);
53 // If this instance contains no plugins with a 'cacheWillUpdate' callback,
54 // prepend the `cacheOkAndOpaquePlugin` plugin to the plugins list.
55 if (!this.plugins.some((p) => 'cacheWillUpdate' in p)) {
56 this.plugins.unshift(cacheOkAndOpaquePlugin);
57 }
58 this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0;
59 if (process.env.NODE_ENV !== 'production') {
60 if (this._networkTimeoutSeconds) {
61 assert.isType(this._networkTimeoutSeconds, 'number', {
62 moduleName: 'workbox-strategies',
63 className: this.constructor.name,
64 funcName: 'constructor',
65 paramName: 'networkTimeoutSeconds',
66 });
67 }
68 }
69 }
70 /**
71 * @private
72 * @param {Request|string} request A request to run this strategy for.
73 * @param {workbox-strategies.StrategyHandler} handler The event that
74 * triggered the request.
75 * @return {Promise<Response>}
76 */
77 async _handle(request, handler) {
78 const logs = [];
79 if (process.env.NODE_ENV !== 'production') {
80 assert.isInstance(request, Request, {
81 moduleName: 'workbox-strategies',
82 className: this.constructor.name,
83 funcName: 'handle',
84 paramName: 'makeRequest',
85 });
86 }
87 const promises = [];
88 let timeoutId;
89 if (this._networkTimeoutSeconds) {
90 const { id, promise } = this._getTimeoutPromise({ request, logs, handler });
91 timeoutId = id;
92 promises.push(promise);
93 }
94 const networkPromise = this._getNetworkPromise({
95 timeoutId,
96 request,
97 logs,
98 handler,
99 });
100 promises.push(networkPromise);
101 const response = await handler.waitUntil((async () => {
102 // Promise.race() will resolve as soon as the first promise resolves.
103 return ((await handler.waitUntil(Promise.race(promises))) ||
104 // If Promise.race() resolved with null, it might be due to a network
105 // timeout + a cache miss. If that were to happen, we'd rather wait until
106 // the networkPromise resolves instead of returning null.
107 // Note that it's fine to await an already-resolved promise, so we don't
108 // have to check to see if it's still "in flight".
109 (await networkPromise));
110 })());
111 if (process.env.NODE_ENV !== 'production') {
112 logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));
113 for (const log of logs) {
114 logger.log(log);
115 }
116 messages.printFinalResponse(response);
117 logger.groupEnd();
118 }
119 if (!response) {
120 throw new WorkboxError('no-response', { url: request.url });
121 }
122 return response;
123 }
124 /**
125 * @param {Object} options
126 * @param {Request} options.request
127 * @param {Array} options.logs A reference to the logs array
128 * @param {Event} options.event
129 * @return {Promise<Response>}
130 *
131 * @private
132 */
133 _getTimeoutPromise({ request, logs, handler, }) {
134 let timeoutId;
135 const timeoutPromise = new Promise((resolve) => {
136 const onNetworkTimeout = async () => {
137 if (process.env.NODE_ENV !== 'production') {
138 logs.push(`Timing out the network response at ` +
139 `${this._networkTimeoutSeconds} seconds.`);
140 }
141 resolve(await handler.cacheMatch(request));
142 };
143 timeoutId = setTimeout(onNetworkTimeout, this._networkTimeoutSeconds * 1000);
144 });
145 return {
146 promise: timeoutPromise,
147 id: timeoutId,
148 };
149 }
150 /**
151 * @param {Object} options
152 * @param {number|undefined} options.timeoutId
153 * @param {Request} options.request
154 * @param {Array} options.logs A reference to the logs Array.
155 * @param {Event} options.event
156 * @return {Promise<Response>}
157 *
158 * @private
159 */
160 async _getNetworkPromise({ timeoutId, request, logs, handler, }) {
161 let error;
162 let response;
163 try {
164 response = await handler.fetchAndCachePut(request);
165 }
166 catch (fetchError) {
167 if (fetchError instanceof Error) {
168 error = fetchError;
169 }
170 }
171 if (timeoutId) {
172 clearTimeout(timeoutId);
173 }
174 if (process.env.NODE_ENV !== 'production') {
175 if (response) {
176 logs.push(`Got response from network.`);
177 }
178 else {
179 logs.push(`Unable to get a response from the network. Will respond ` +
180 `with a cached response.`);
181 }
182 }
183 if (error || !response) {
184 response = await handler.cacheMatch(request);
185 if (process.env.NODE_ENV !== 'production') {
186 if (response) {
187 logs.push(`Found a cached response in the '${this.cacheName}'` + ` cache.`);
188 }
189 else {
190 logs.push(`No response found in the '${this.cacheName}' cache.`);
191 }
192 }
193 }
194 return response;
195 }
196}
197export { NetworkFirst };
Note: See TracBrowser for help on using the repository browser.