Front end of the Slack clone application.

networkFirst.js 3.5KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. Copyright 2015 Google Inc. All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. 'use strict';
  14. var globalOptions = require('../options');
  15. var helpers = require('../helpers');
  16. function networkFirst(request, values, options) {
  17. options = options || {};
  18. var successResponses = options.successResponses ||
  19. globalOptions.successResponses;
  20. // This will bypass options.networkTimeout if it's set to a false-y value like
  21. // 0, but that's the sane thing to do anyway.
  22. var networkTimeoutSeconds = options.networkTimeoutSeconds ||
  23. globalOptions.networkTimeoutSeconds;
  24. helpers.debug('Strategy: network first [' + request.url + ']', options);
  25. return helpers.openCache(options).then(function(cache) {
  26. var timeoutId;
  27. var promises = [];
  28. var originalResponse;
  29. if (networkTimeoutSeconds) {
  30. var cacheWhenTimedOutPromise = new Promise(function(resolve) {
  31. timeoutId = setTimeout(function() {
  32. cache.match(request).then(function(response) {
  33. var cacheOptions = options.cache || globalOptions.cache;
  34. // Only resolve this promise if there's a valid response in the
  35. // cache. This ensures that we won't time out a network request
  36. // unless there's a cached entry to fallback on, which is arguably
  37. // the preferable behavior.
  38. var now = Date.now();
  39. var maxAgeSeconds = cacheOptions.maxAgeSeconds;
  40. if (helpers.isResponseFresh(response, maxAgeSeconds, now)) {
  41. resolve(response);
  42. }
  43. });
  44. }, networkTimeoutSeconds * 1000);
  45. });
  46. promises.push(cacheWhenTimedOutPromise);
  47. }
  48. var networkPromise = helpers.fetchAndCache(request, options)
  49. .then(function(response) {
  50. // We've got a response, so clear the network timeout if there is one.
  51. if (timeoutId) {
  52. clearTimeout(timeoutId);
  53. }
  54. if (successResponses.test(response.status)) {
  55. return response;
  56. }
  57. helpers.debug('Response was an HTTP error: ' + response.statusText,
  58. options);
  59. originalResponse = response;
  60. throw new Error('Bad response');
  61. }).catch(function(error) {
  62. helpers.debug('Network or response error, fallback to cache [' +
  63. request.url + ']', options);
  64. return cache.match(request).then(function(response) {
  65. // If there's a match in the cache, resolve with that.
  66. if (response) {
  67. return response;
  68. }
  69. // If we have a Response object from the previous fetch, then resolve
  70. // with that, even though it corresponds to an error status code.
  71. if (originalResponse) {
  72. return originalResponse;
  73. }
  74. // If we don't have a Response object from the previous fetch, likely
  75. // due to a network failure, then reject with the failure error.
  76. throw error;
  77. });
  78. });
  79. promises.push(networkPromise);
  80. return Promise.race(promises);
  81. });
  82. }
  83. module.exports = networkFirst;