Skip to content

Commit

Permalink
fix(Watcher): then() emits wrong value
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Works committed Aug 8, 2019
1 parent 8c9589f commit 820aca8
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 27 deletions.
3 changes: 2 additions & 1 deletion api-documents/kit.watcher.then.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Start the watcher, once it emitted data, stop watching.
```typescript
then<TResult1 = ResultOf<SingleMode, T>, TResult2 = never>(onfulfilled?: ((value: ResultOf<SingleMode, T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null, options?: {
minimalResultsRequired?: number;
timeout?: number;
}, starter?: (this: this, self: this) => void): Promise<TResult1 | TResult2>;
```

Expand All @@ -20,7 +21,7 @@ then<TResult1 = ResultOf<SingleMode, T>, TResult2 = never>(onfulfilled?: ((value
| --- | --- | --- |
| onfulfilled | <code>((value: ResultOf&lt;SingleMode, T&gt;) =&gt; TResult1 &#124; PromiseLike&lt;TResult1&gt;) &#124; null</code> | |
| onrejected | <code>((reason: any) =&gt; TResult2 &#124; PromiseLike&lt;TResult2&gt;) &#124; null</code> | |
| options | <code>{</code><br/><code> minimalResultsRequired?: number;</code><br/><code> }</code> | Options for watcher |
| options | <code>{</code><br/><code> minimalResultsRequired?: number;</code><br/><code> timeout?: number;</code><br/><code> }</code> | Options for watcher |
| starter | <code>(this: this, self: this) =&gt; void</code> | How to start the watcher |

<b>Returns:</b>
Expand Down
1 change: 1 addition & 0 deletions doc/holoflows-kit.api.report.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ export abstract class Watcher<T, Before extends Element, After extends Element,
stopWatch(...args: any[]): void;
then<TResult1 = ResultOf<SingleMode, T>, TResult2 = never>(onfulfilled?: ((value: ResultOf<SingleMode, T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null, options?: {
minimalResultsRequired?: number;
timeout?: number;
}, starter?: (this: this, self: this) => void): Promise<TResult1 | TResult2>;
// Warning: (ae-forgotten-export) The symbol "useForeachReturns" needs to be exported by the entry point index.d.ts
useForeach(forEach: (virtualNode: T, key: unknown, metadata: T extends Node ? DomProxy<T, Before, After> : unknown) => useForeachReturns<T>): this;
Expand Down
36 changes: 19 additions & 17 deletions src/DOM/Watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import intersectionWith from 'lodash-es/intersectionWith'
import uniqWith from 'lodash-es/uniqWith'
import { Deadline, requestIdleCallback } from '../util/requestIdleCallback'
import { isNil } from 'lodash-es'
import { timeout } from '../util/sleep'

/**
* Use LiveSelector to watch dom change
Expand Down Expand Up @@ -137,16 +138,18 @@ export abstract class Watcher<T, Before extends Element, After extends Element,
public then<TResult1 = ResultOf<SingleMode, T>, TResult2 = never>(
onfulfilled?: ((value: ResultOf<SingleMode, T>) => TResult1 | PromiseLike<TResult1>) | null,
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,
options: { minimalResultsRequired?: number } = {},
options: { minimalResultsRequired?: number; timeout?: number } = {},
starter: (this: this, self: this) => void = watcher => watcher.startWatch(),
): Promise<TResult1 | TResult2> {
const { minimalResultsRequired } = {
this._warning_forget_watch_.ignored = true
const { minimalResultsRequired, timeout: timeoutTime } = {
...({
minimalResultsRequired: 1,
timeout: Infinity,
} as Required<typeof options>),
...options,
}
const map = onfulfilled || (x => x)
let done: (state: boolean, val: any) => void
const then = async () => {
if (minimalResultsRequired < 1)
throw new TypeError('Invalid minimalResultsRequired, must equal to or bigger than 1')
Expand All @@ -156,29 +159,34 @@ export abstract class Watcher<T, Before extends Element, After extends Element,
const result = this.liveSelector.evaluateOnce()
if (Array.isArray(result) && result.length >= minimalResultsRequired) {
// If we get the value now, return it
return result.map(v => map(v))
return result
} else if (this.singleMode) {
// If in single mode, return the value now
return result
}
// Or return a promise to wait the value
return new Promise<ResultOf<SingleMode, TResult1>>((resolve, reject) => {
done = (state, val) => {
this.stopWatch()
this.removeListener('onIteration', f)
if (state) resolve(val)
else reject(val)
}
starter.bind(this)(this)
const f: EventCallback<OnIterationEvent<T>> = v => {
const f = (v: OnIterationEvent<any>) => {
const nodes = v.values.current
if (this.singleMode && nodes.length >= 1) {
const returns = map(nodes[0] as ResultOf<SingleMode, T>)
resolve(Promise.resolve(returns as any))
return done(true, nodes[0])
}
if (nodes.length < minimalResultsRequired) return
this.stopWatch()
Promise.all(nodes.map(map as any)).then(resolve as any, reject)
this.removeListener('onIteration', f)
return done(true, nodes)
}
this.addListener('onIteration', f)
})
}
return then().then(onfulfilled, onrejected)
const withTimeout = timeout(then(), timeoutTime)
withTimeout.finally(() => done(false, new Error('timeout')))
return withTimeout.then(onfulfilled, onrejected)
}
//#endregion
//#region Multiple mode
Expand Down Expand Up @@ -723,12 +731,6 @@ type useForeachReturns<T> =
onNodeMutation?: MutationCallback<T>
}

type useForeachFnWithNode<T, Before extends Element, After extends Element> = {
(virtualNode: T, key: unknown, metadata: T extends Node ? DomProxy<T, Before, After> : unknown): useForeachReturns<
T
>
}

function applyUseForeachCallback<T>(callback: useForeachReturns<T>) {
const cb = callback as useForeachReturns<Node>
let remove: any, change: any, mutation: any
Expand Down
21 changes: 12 additions & 9 deletions src/util/sleep.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { requestIdleCallback } from './requestIdleCallback'

/**
* Return a promise that resolved after `time` ms.
* If `time` is `Infinity`, it will never resolve.
Expand All @@ -18,10 +16,15 @@ export const sleep = (time: number) =>
*
* @internal
*/
export const timeout = <T>(promise: PromiseLike<T>, time: number, rejectReason?: string) =>
Number.isFinite(time)
? Promise.race([
promise,
new Promise<T>((r, reject) => setTimeout(() => reject(new Error(rejectReason || 'timeout')), time)),
])
: promise
export const timeout = <T>(promise: PromiseLike<T>, time: number, rejectReason?: string): Promise<T> => {
if (!Number.isFinite(time)) return (async () => promise)()
let timer: any
const race = Promise.race([
promise,
new Promise<T>((r, reject) => {
timer = setTimeout(() => reject(new Error(rejectReason || 'timeout')), time)
}),
])
race.finally(() => clearTimeout(timer))
return race
}

0 comments on commit 820aca8

Please sign in to comment.