1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- /*
- Copyright 2015 Google Inc. All Rights Reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- 'use strict';
- var globalOptions = require('../options');
- var helpers = require('../helpers');
-
- function networkFirst(request, values, options) {
- options = options || {};
- var successResponses = options.successResponses ||
- globalOptions.successResponses;
- // This will bypass options.networkTimeout if it's set to a false-y value like
- // 0, but that's the sane thing to do anyway.
- var networkTimeoutSeconds = options.networkTimeoutSeconds ||
- globalOptions.networkTimeoutSeconds;
- helpers.debug('Strategy: network first [' + request.url + ']', options);
-
- return helpers.openCache(options).then(function(cache) {
- var timeoutId;
- var promises = [];
- var originalResponse;
-
- if (networkTimeoutSeconds) {
- var cacheWhenTimedOutPromise = new Promise(function(resolve) {
- timeoutId = setTimeout(function() {
- cache.match(request).then(function(response) {
- var cacheOptions = options.cache || globalOptions.cache;
- // Only resolve this promise if there's a valid response in the
- // cache. This ensures that we won't time out a network request
- // unless there's a cached entry to fallback on, which is arguably
- // the preferable behavior.
- var now = Date.now();
- var maxAgeSeconds = cacheOptions.maxAgeSeconds;
- if (helpers.isResponseFresh(response, maxAgeSeconds, now)) {
- resolve(response);
- }
- });
- }, networkTimeoutSeconds * 1000);
- });
- promises.push(cacheWhenTimedOutPromise);
- }
-
- var networkPromise = helpers.fetchAndCache(request, options)
- .then(function(response) {
- // We've got a response, so clear the network timeout if there is one.
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
-
- if (successResponses.test(response.status)) {
- return response;
- }
-
- helpers.debug('Response was an HTTP error: ' + response.statusText,
- options);
- originalResponse = response;
- throw new Error('Bad response');
- }).catch(function(error) {
- helpers.debug('Network or response error, fallback to cache [' +
- request.url + ']', options);
- return cache.match(request).then(function(response) {
- // If there's a match in the cache, resolve with that.
- if (response) {
- return response;
- }
-
- // If we have a Response object from the previous fetch, then resolve
- // with that, even though it corresponds to an error status code.
- if (originalResponse) {
- return originalResponse;
- }
-
- // If we don't have a Response object from the previous fetch, likely
- // due to a network failure, then reject with the failure error.
- throw error;
- });
- });
-
- promises.push(networkPromise);
-
- return Promise.race(promises);
- });
- }
-
- module.exports = networkFirst;
|