UNPKG

5.14 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.ObservablePromise = void 0;
4const observable_fns_1 = require("observable-fns");
5const doNothing = () => undefined;
6const returnInput = (input) => input;
7const runDeferred = (fn) => Promise.resolve().then(fn);
8function fail(error) {
9 throw error;
10}
11function isThenable(thing) {
12 return thing && typeof thing.then === "function";
13}
14/**
15 * Creates a hybrid, combining the APIs of an Observable and a Promise.
16 *
17 * It is used to proxy async process states when we are initially not sure
18 * if that async process will yield values once (-> Promise) or multiple
19 * times (-> Observable).
20 *
21 * Note that the observable promise inherits some of the observable's characteristics:
22 * The `init` function will be called *once for every time anyone subscribes to it*.
23 *
24 * If this is undesired, derive a hot observable from it using `makeHot()` and
25 * subscribe to that.
26 */
27class ObservablePromise extends observable_fns_1.Observable {
28 constructor(init) {
29 super((originalObserver) => {
30 // tslint:disable-next-line no-this-assignment
31 const self = this;
32 const observer = Object.assign(Object.assign({}, originalObserver), { complete() {
33 originalObserver.complete();
34 self.onCompletion();
35 }, error(error) {
36 originalObserver.error(error);
37 self.onError(error);
38 },
39 next(value) {
40 originalObserver.next(value);
41 self.onNext(value);
42 } });
43 try {
44 this.initHasRun = true;
45 return init(observer);
46 }
47 catch (error) {
48 observer.error(error);
49 }
50 });
51 this.initHasRun = false;
52 this.fulfillmentCallbacks = [];
53 this.rejectionCallbacks = [];
54 this.firstValueSet = false;
55 this.state = "pending";
56 }
57 onNext(value) {
58 if (!this.firstValueSet) {
59 this.firstValue = value;
60 this.firstValueSet = true;
61 }
62 }
63 onError(error) {
64 this.state = "rejected";
65 this.rejection = error;
66 for (const onRejected of this.rejectionCallbacks) {
67 // Promisifying the call to turn errors into unhandled promise rejections
68 // instead of them failing sync and cancelling the iteration
69 runDeferred(() => onRejected(error));
70 }
71 }
72 onCompletion() {
73 this.state = "fulfilled";
74 for (const onFulfilled of this.fulfillmentCallbacks) {
75 // Promisifying the call to turn errors into unhandled promise rejections
76 // instead of them failing sync and cancelling the iteration
77 runDeferred(() => onFulfilled(this.firstValue));
78 }
79 }
80 then(onFulfilledRaw, onRejectedRaw) {
81 const onFulfilled = onFulfilledRaw || returnInput;
82 const onRejected = onRejectedRaw || fail;
83 let onRejectedCalled = false;
84 return new Promise((resolve, reject) => {
85 const rejectionCallback = (error) => {
86 if (onRejectedCalled)
87 return;
88 onRejectedCalled = true;
89 try {
90 resolve(onRejected(error));
91 }
92 catch (anotherError) {
93 reject(anotherError);
94 }
95 };
96 const fulfillmentCallback = (value) => {
97 try {
98 resolve(onFulfilled(value));
99 }
100 catch (error) {
101 rejectionCallback(error);
102 }
103 };
104 if (!this.initHasRun) {
105 this.subscribe({ error: rejectionCallback });
106 }
107 if (this.state === "fulfilled") {
108 return resolve(onFulfilled(this.firstValue));
109 }
110 if (this.state === "rejected") {
111 onRejectedCalled = true;
112 return resolve(onRejected(this.rejection));
113 }
114 this.fulfillmentCallbacks.push(fulfillmentCallback);
115 this.rejectionCallbacks.push(rejectionCallback);
116 });
117 }
118 catch(onRejected) {
119 return this.then(undefined, onRejected);
120 }
121 finally(onCompleted) {
122 const handler = onCompleted || doNothing;
123 return this.then((value) => {
124 handler();
125 return value;
126 }, () => handler());
127 }
128 static from(thing) {
129 if (isThenable(thing)) {
130 return new ObservablePromise(observer => {
131 const onFulfilled = (value) => {
132 observer.next(value);
133 observer.complete();
134 };
135 const onRejected = (error) => {
136 observer.error(error);
137 };
138 thing.then(onFulfilled, onRejected);
139 });
140 }
141 else {
142 return super.from(thing);
143 }
144 }
145}
146exports.ObservablePromise = ObservablePromise;