Source: lib/polyfill/abort_controller.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.polyfill.AbortController');
  7. goog.require('shaka.polyfill');
  8. goog.require('shaka.util.FakeEvent');
  9. goog.require('shaka.util.FakeEventTarget');
  10. /**
  11. * @summary A polyfill for systems that do not implement AbortController.
  12. * This is used both with the fetch API for HTTP requests and inside the HLS
  13. * parser.
  14. * @export
  15. * @extends AbortController
  16. */
  17. shaka.polyfill.AbortController = class {
  18. /**
  19. * Install the polyfill if needed.
  20. * @export
  21. */
  22. static install() {
  23. if (window.AbortController) {
  24. // Not needed.
  25. return;
  26. }
  27. window.AbortController = shaka.polyfill.AbortController;
  28. window.AbortSignal = shaka.polyfill.AbortController.AbortSignal;
  29. }
  30. /** */
  31. constructor() {
  32. /** @private {!shaka.polyfill.AbortController.AbortSignal} */
  33. this.signal_ = new shaka.polyfill.AbortController.AbortSignal();
  34. }
  35. /**
  36. * @override
  37. * @suppress {const|duplicate} Since the original is defined as "const", we
  38. * need this suppression to override it.
  39. */
  40. get signal() {
  41. return this.signal_;
  42. }
  43. /**
  44. * @param {*=} reason
  45. * @override
  46. */
  47. abort(reason) {
  48. this.signal_.doAbort_(reason);
  49. }
  50. };
  51. /**
  52. * @summary A polyfill for AbortSignal, part of the AbortController API.
  53. * @extends AbortSignal
  54. */
  55. shaka.polyfill.AbortController.AbortSignal = class {
  56. /** */
  57. constructor() {
  58. /** @private {boolean} */
  59. this.aborted_ = false;
  60. /** @private {*} */
  61. this.reason_ = undefined;
  62. /** @type {?function(!Event)} */
  63. this.onabort = null;
  64. /** @private {!shaka.util.FakeEventTarget} */
  65. this.eventTarget_ = new shaka.util.FakeEventTarget();
  66. }
  67. /** @override */
  68. addEventListener(type, listener, options) {
  69. return this.eventTarget_.addEventListener(type, listener, options);
  70. }
  71. /** @override */
  72. removeEventListener(type, listener, options) {
  73. return this.eventTarget_.removeEventListener(type, listener, options);
  74. }
  75. /** @override */
  76. dispatchEvent(event) {
  77. return this.eventTarget_.dispatchEvent(event);
  78. }
  79. /** @override */
  80. get aborted() {
  81. return this.aborted_;
  82. }
  83. /** @override */
  84. get reason() {
  85. return this.reason_;
  86. }
  87. /** @override */
  88. throwIfAborted() {
  89. if (this.aborted_) {
  90. throw this.reason_;
  91. }
  92. }
  93. /**
  94. * @param {*} reason
  95. * @private
  96. */
  97. doAbort_(reason) {
  98. if (this.aborted_) {
  99. return;
  100. }
  101. this.aborted_ = true;
  102. this.reason_ = reason;
  103. if (this.reason_ === undefined) {
  104. // This is equivalent to a native implementation.
  105. this.reason_ = new DOMException(
  106. 'signal is aborted without reason', 'AbortError');
  107. }
  108. // According to MDN:
  109. // "Event type - A generic Event with no added properties."
  110. const event = new shaka.util.FakeEvent('abort');
  111. if (this.onabort) {
  112. this.onabort(event);
  113. }
  114. this.dispatchEvent(event);
  115. }
  116. /** @override */
  117. static abort(reason) {
  118. const signal = new shaka.polyfill.AbortController.AbortSignal();
  119. signal.doAbort_(reason);
  120. return signal;
  121. }
  122. /** @override */
  123. static timeout(timeMs) {
  124. const signal = new shaka.polyfill.AbortController.AbortSignal();
  125. window.setTimeout(() => {
  126. // This is equivalent to a native implementation.
  127. signal.doAbort_(new DOMException('signal timed out', 'TimeoutError'));
  128. }, timeMs);
  129. return signal;
  130. }
  131. };
  132. shaka.polyfill.register(shaka.polyfill.AbortController.install);