| 4 | import { observe } from './observe'; |
| 5 | |
| 6 | function _when<T>(predicate: Selector<T>, effect?: (value: T) => any | (() => any), checkReady?: boolean): Promise<T> { |
| 7 | // If predicate is a regular Promise skip all the observable stuff |
| 8 | if (isPromise<T>(predicate)) { |
| 9 | return effect ? predicate.then(effect) : predicate; |
| 10 | } |
| 11 | |
| 12 | let value: T | undefined; |
| 13 | |
| 14 | // Create a wrapping fn that calls the effect if predicate returns true |
| 15 | function run(e: ObserveEvent<T>) { |
| 16 | const ret = computeSelector(predicate); |
| 17 | |
| 18 | if (!isPromise(ret) && (checkReady ? isObservableValueReady(ret) : ret)) { |
| 19 | value = ret; |
| 20 | |
| 21 | // Set cancel so that observe does not track anymore |
| 22 | e.cancel = true; |
| 23 | } |
| 24 | |
| 25 | return value; |
| 26 | } |
| 27 | function doEffect() { |
| 28 | // If value is truthy then run the effect |
| 29 | effect?.(value!); |
| 30 | } |
| 31 | // Run in an observe |
| 32 | observe(run, doEffect); |
| 33 | |
| 34 | // If first run resulted in a truthy value just return it. |
| 35 | // It will have set e.cancel so no need to dispose |
| 36 | if (isPromise<T>(value)) { |
| 37 | return effect ? value.then(effect) : value; |
| 38 | } else if (value !== undefined) { |
| 39 | return Promise.resolve(value); |
| 40 | } else { |
| 41 | // Wrap it in a promise |
| 42 | const promise = new Promise<T>((resolve) => { |
| 43 | if (effect) { |
| 44 | const originalEffect = effect; |
| 45 | effect = (value) => { |
| 46 | const effectValue = originalEffect(value); |
| 47 | resolve(effectValue); |
| 48 | }; |
| 49 | } else { |
| 50 | effect = resolve; |
| 51 | } |
| 52 | }); |
| 53 | |
| 54 | return promise; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | export function when<T>(predicate: Selector<T>, effect?: (value: T) => any | (() => any)): Promise<T> { |
| 59 | return _when<T>(predicate, effect, false); |