zone-patch-fetch.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. 'use strict';
  2. /**
  3. * @license Angular v<unknown>
  4. * (c) 2010-2022 Google LLC. https://angular.io/
  5. * License: MIT
  6. */
  7. /**
  8. * @fileoverview
  9. * @suppress {missingRequire}
  10. */
  11. Zone.__load_patch('fetch', (global, Zone, api) => {
  12. let fetch = global['fetch'];
  13. if (typeof fetch !== 'function') {
  14. return;
  15. }
  16. const originalFetch = global[api.symbol('fetch')];
  17. if (originalFetch) {
  18. // restore unpatched fetch first
  19. fetch = originalFetch;
  20. }
  21. const ZoneAwarePromise = global.Promise;
  22. const symbolThenPatched = api.symbol('thenPatched');
  23. const fetchTaskScheduling = api.symbol('fetchTaskScheduling');
  24. const fetchTaskAborting = api.symbol('fetchTaskAborting');
  25. const OriginalAbortController = global['AbortController'];
  26. const supportAbort = typeof OriginalAbortController === 'function';
  27. let abortNative = null;
  28. if (supportAbort) {
  29. global['AbortController'] = function () {
  30. const abortController = new OriginalAbortController();
  31. const signal = abortController.signal;
  32. signal.abortController = abortController;
  33. return abortController;
  34. };
  35. abortNative = api.patchMethod(OriginalAbortController.prototype, 'abort', (delegate) => (self, args) => {
  36. if (self.task) {
  37. return self.task.zone.cancelTask(self.task);
  38. }
  39. return delegate.apply(self, args);
  40. });
  41. }
  42. const placeholder = function () { };
  43. global['fetch'] = function () {
  44. const args = Array.prototype.slice.call(arguments);
  45. const options = args.length > 1 ? args[1] : null;
  46. const signal = options && options.signal;
  47. return new Promise((res, rej) => {
  48. const task = Zone.current.scheduleMacroTask('fetch', placeholder, { fetchArgs: args }, () => {
  49. let fetchPromise;
  50. let zone = Zone.current;
  51. try {
  52. zone[fetchTaskScheduling] = true;
  53. fetchPromise = fetch.apply(this, args);
  54. }
  55. catch (error) {
  56. rej(error);
  57. return;
  58. }
  59. finally {
  60. zone[fetchTaskScheduling] = false;
  61. }
  62. if (!(fetchPromise instanceof ZoneAwarePromise)) {
  63. let ctor = fetchPromise.constructor;
  64. if (!ctor[symbolThenPatched]) {
  65. api.patchThen(ctor);
  66. }
  67. }
  68. fetchPromise.then((resource) => {
  69. if (task.state !== 'notScheduled') {
  70. task.invoke();
  71. }
  72. res(resource);
  73. }, (error) => {
  74. if (task.state !== 'notScheduled') {
  75. task.invoke();
  76. }
  77. rej(error);
  78. });
  79. }, () => {
  80. if (!supportAbort) {
  81. rej('No AbortController supported, can not cancel fetch');
  82. return;
  83. }
  84. if (signal && signal.abortController && !signal.aborted &&
  85. typeof signal.abortController.abort === 'function' && abortNative) {
  86. try {
  87. Zone.current[fetchTaskAborting] = true;
  88. abortNative.call(signal.abortController);
  89. }
  90. finally {
  91. Zone.current[fetchTaskAborting] = false;
  92. }
  93. }
  94. else {
  95. rej('cancel fetch need a AbortController.signal');
  96. }
  97. });
  98. if (signal && signal.abortController) {
  99. signal.abortController.task = task;
  100. }
  101. });
  102. };
  103. });