You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

strategy.mjs 2.9 KiB

3 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. /*
  2. Copyright 2018 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. import {logger} from 'workbox-core/_private/logger.mjs';
  14. import {createHeaders} from './utils/createHeaders.mjs';
  15. import {concatenateToResponse} from './concatenateToResponse.mjs';
  16. import {isSupported} from './isSupported.mjs';
  17. import './_version.mjs';
  18. /**
  19. * A shortcut to create a strategy that could be dropped-in to Workbox's router.
  20. *
  21. * On browsers that do not support constructing new `ReadableStream`s, this
  22. * strategy will automatically wait for all the `sourceFunctions` to complete,
  23. * and create a final response that concatenates their values together.
  24. *
  25. * @param {
  26. * Array<function(workbox.routing.Route~handlerCallback)>} sourceFunctions
  27. * Each function should return a {@link workbox.streams.StreamSource} (or a
  28. * Promise which resolves to one).
  29. * @param {HeadersInit} [headersInit] If there's no `Content-Type` specified,
  30. * `'text/html'` will be used by default.
  31. * @return {workbox.routing.Route~handlerCallback}
  32. *
  33. * @memberof workbox.streams
  34. */
  35. export function strategy(sourceFunctions, headersInit) {
  36. return async ({event, url, params}) => {
  37. if (isSupported()) {
  38. const {done, response} = concatenateToResponse(sourceFunctions.map(
  39. (sourceFunction) => sourceFunction({event, url, params})), headersInit);
  40. event.waitUntil(done);
  41. return response;
  42. }
  43. if (process.env.NODE_ENV !== 'production') {
  44. logger.log(`The current browser doesn't support creating response ` +
  45. `streams. Falling back to non-streaming response instead.`);
  46. }
  47. // Fallback to waiting for everything to finish, and concatenating the
  48. // responses.
  49. const parts = await Promise.all(
  50. sourceFunctions.map(
  51. (sourceFunction) => sourceFunction({event, url, params})
  52. ).map(async (responsePromise) => {
  53. const response = await responsePromise;
  54. if (response instanceof Response) {
  55. return response.blob();
  56. }
  57. // Otherwise, assume it's something like a string which can be used
  58. // as-is when constructing the final composite blob.
  59. return response;
  60. })
  61. );
  62. const headers = createHeaders(headersInit);
  63. // Constructing a new Response from a Blob source is well-supported.
  64. // So is constructing a new Blob from multiple source Blobs or strings.
  65. return new Response(new Blob(parts), {headers});
  66. };
  67. }