1 | import {
|
2 | $mobx,
|
3 | IReactionDisposer,
|
4 | Lambda,
|
5 | autorun,
|
6 | createAction,
|
7 | getNextId,
|
8 | die,
|
9 | allowStateChanges
|
10 | } from "../internal"
|
11 |
|
12 | export interface IWhenOptions {
|
13 | name?: string
|
14 | timeout?: number
|
15 | onError?: (error: any) => void
|
16 | }
|
17 |
|
18 | export function when(
|
19 | predicate: () => boolean,
|
20 | opts?: IWhenOptions
|
21 | ): Promise<void> & { cancel(): void }
|
22 | export function when(
|
23 | predicate: () => boolean,
|
24 | effect: Lambda,
|
25 | opts?: IWhenOptions
|
26 | ): IReactionDisposer
|
27 | export function when(predicate: any, arg1?: any, arg2?: any): any {
|
28 | if (arguments.length === 1 || (arg1 && typeof arg1 === "object"))
|
29 | return whenPromise(predicate, arg1)
|
30 | return _when(predicate, arg1, arg2 || {})
|
31 | }
|
32 |
|
33 | function _when(predicate: () => boolean, effect: Lambda, opts: IWhenOptions): IReactionDisposer {
|
34 | let timeoutHandle: any
|
35 | if (typeof opts.timeout === "number") {
|
36 | const error = new Error("WHEN_TIMEOUT")
|
37 | timeoutHandle = setTimeout(() => {
|
38 | if (!disposer[$mobx].isDisposed_) {
|
39 | disposer()
|
40 | if (opts.onError) opts.onError(error)
|
41 | else throw error
|
42 | }
|
43 | }, opts.timeout)
|
44 | }
|
45 |
|
46 | opts.name = __DEV__ ? opts.name || "When@" + getNextId() : "When"
|
47 | const effectAction = createAction(
|
48 | __DEV__ ? opts.name + "-effect" : "When-effect",
|
49 | effect as Function
|
50 | )
|
51 |
|
52 | var disposer = autorun(r => {
|
53 |
|
54 | let cond = allowStateChanges(false, predicate)
|
55 | if (cond) {
|
56 | r.dispose()
|
57 | if (timeoutHandle) clearTimeout(timeoutHandle)
|
58 | effectAction()
|
59 | }
|
60 | }, opts)
|
61 | return disposer
|
62 | }
|
63 |
|
64 | function whenPromise(
|
65 | predicate: () => boolean,
|
66 | opts?: IWhenOptions
|
67 | ): Promise<void> & { cancel(): void } {
|
68 | if (__DEV__ && opts && opts.onError)
|
69 | return die(`the options 'onError' and 'promise' cannot be combined`)
|
70 | let cancel
|
71 | const res = new Promise((resolve, reject) => {
|
72 | let disposer = _when(predicate, resolve, { ...opts, onError: reject })
|
73 | cancel = () => {
|
74 | disposer()
|
75 | reject(new Error("WHEN_CANCELLED"))
|
76 | }
|
77 | })
|
78 | ;(res as any).cancel = cancel
|
79 | return res as any
|
80 | }
|