UNPKG

3.71 kBJavaScriptView Raw
1class Emitter {
2 constructor() {
3 Object.defineProperty(this, 'listeners', { value: {}, writable: true, configurable: true });
4 }
5 addEventListener(type, callback) {
6 if (!(type in this.listeners)) {
7 this.listeners[type] = [];
8 }
9 this.listeners[type].push(callback);
10 }
11 removeEventListener(type, callback) {
12 if (!(type in this.listeners)) {
13 return;
14 }
15 const stack = this.listeners[type];
16 for (let i = 0, l = stack.length; i < l; i++) {
17 if (stack[i] === callback) {
18 stack.splice(i, 1);
19 return;
20 }
21 }
22 }
23 dispatchEvent(event) {
24 if (!(event.type in this.listeners)) {
25 return;
26 }
27 const stack = this.listeners[event.type];
28 for (let i = 0, l = stack.length; i < l; i++) {
29 try {
30 stack[i].call(this, event);
31 } catch (e) {
32 Promise.resolve().then(() => { throw e; });
33 }
34 }
35 return !event.defaultPrevented;
36 }
37}
38
39export class AbortSignal extends Emitter {
40 constructor() {
41 super();
42 // Some versions of babel does not transpile super() correctly for IE <= 10, if the parent
43 // constructor has failed to run, then "this.listeners" will still be undefined and then we call
44 // the parent constructor directly instead as a workaround. For general details, see babel bug:
45 // https://github.com/babel/babel/issues/3041
46 // This hack was added as a fix for the issue described here:
47 // https://github.com/Financial-Times/polyfill-library/pull/59#issuecomment-477558042
48 if (!this.listeners) {
49 Emitter.call(this);
50 }
51
52 // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
53 // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl
54 Object.defineProperty(this, 'aborted', { value: false, writable: true, configurable: true });
55 Object.defineProperty(this, 'onabort', { value: null, writable: true, configurable: true });
56 }
57 toString() {
58 return '[object AbortSignal]';
59 }
60 dispatchEvent(event) {
61 if (event.type === 'abort') {
62 this.aborted = true;
63 if (typeof this.onabort === 'function') {
64 this.onabort.call(this, event);
65 }
66 }
67
68 super.dispatchEvent(event);
69 }
70}
71
72export class AbortController {
73 constructor() {
74 // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
75 // we want Object.keys(new AbortController()) to be [] for compat with the native impl
76 Object.defineProperty(this, 'signal', { value: new AbortSignal(), writable: true, configurable: true });
77 }
78 abort() {
79 let event;
80 try {
81 event = new Event('abort');
82 } catch (e) {
83 if (typeof document !== 'undefined') {
84 if (!document.createEvent) {
85 // For Internet Explorer 8:
86 event = document.createEventObject();
87 event.type = 'abort';
88 } else {
89 // For Internet Explorer 11:
90 event = document.createEvent('Event');
91 event.initEvent('abort', false, false);
92 }
93 } else {
94 // Fallback where document isn't available:
95 event = {
96 type: 'abort',
97 bubbles: false,
98 cancelable: false
99 };
100 }
101 }
102 this.signal.dispatchEvent(event);
103 }
104 toString() {
105 return '[object AbortController]';
106 }
107}
108
109export default AbortController;
110
111if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
112 // These are necessary to make sure that we get correct output for:
113 // Object.prototype.toString.call(new AbortController())
114 AbortController.prototype[Symbol.toStringTag] = 'AbortController';
115 AbortSignal.prototype[Symbol.toStringTag] = 'AbortSignal';
116}