Skip to content

Commit b689083

Browse files
committed
chore: refactor runAsync function
- pass an `AnimationTarget` object to `runAsync` function - check for invalidated `runAsync` call whenever an `animate` promise is resolved - only set `state.asyncTo` on a default cancel, because using `cancel: true` without `default: true` should only affect the update it's defined in - use `getResult` functions for brevity
1 parent c008522 commit b689083

File tree

3 files changed

+30
-45
lines changed

3 files changed

+30
-45
lines changed

packages/core/src/Controller.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Lookup, Falsy } from './types/common'
55
import { inferTo } from './helpers'
66
import { FrameValue } from './FrameValue'
77
import { SpringPhase, CREATED, ACTIVE, IDLE } from './SpringPhase'
8+
import { SpringValue, createLoopUpdate, createUpdate } from './SpringValue'
89
import {
910
getCombinedResult,
1011
AnimationResult,
@@ -88,7 +89,7 @@ export class Controller<State extends Lookup = Lookup>
8889
*/
8990
get idle() {
9091
return (
91-
!this._state.promise &&
92+
!this._state.asyncTo &&
9293
Object.values(this.springs as Lookup<SpringValue>).every(
9394
spring => spring.idle
9495
)
@@ -309,24 +310,16 @@ export function flushUpdate(
309310
state,
310311
action(props, resolve) {
311312
props.onRest = onRest as any
312-
resolve(
313-
runAsync(
314-
asyncTo,
315-
props,
316-
state,
317-
ctrl.get.bind(ctrl),
318-
() => false, // TODO: add pausing to Controller
319-
ctrl.start.bind(ctrl) as any,
320-
ctrl.stop.bind(ctrl)
321-
)
322-
)
313+
resolve(runAsync(asyncTo, props, state, ctrl))
323314
},
324315
})
325316
)
326317
}
327-
// Cancel an active "asyncTo" if desired.
318+
// Respect the `cancel` prop when no keys are affected.
328319
else if (!props.keys && props.cancel === true) {
329320
state.cancelId = ctrl['_lastAsyncId']
321+
// Ensure the `idle` property returns true.
322+
state.asyncTo = undefined
330323
}
331324

332325
return Promise.all(promises).then(results => {

packages/core/src/SpringValue.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -786,17 +786,7 @@ export class SpringValue<T = any> extends FrameValue<T> {
786786
}
787787

788788
if (hasAsyncTo) {
789-
resolve(
790-
runAsync(
791-
props.to,
792-
props,
793-
this._state,
794-
() => this.get(),
795-
() => this.is(PAUSED),
796-
this.start.bind(this),
797-
this.stop.bind(this) as any
798-
)
799-
)
789+
resolve(runAsync(props.to, props, this._state, this))
800790
}
801791

802792
// Start an animation

packages/core/src/runAsync.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import {
88
SpringChain,
99
SpringDefaultProps,
1010
SpringProps,
11-
SpringStopFn,
1211
SpringToFn,
1312
} from './types'
1413
import {
14+
getCancelledResult,
15+
getFinishedResult,
1516
AnimationResult,
1617
AsyncResult,
18+
AnimationTarget,
1719
} from './AnimationResult'
1820

1921
export interface RunAsyncProps<T = any> extends SpringProps<T> {
@@ -50,17 +52,14 @@ export async function runAsync<T>(
5052
to: SpringChain<T> | SpringToFn<T>,
5153
props: RunAsyncProps<T>,
5254
state: RunAsyncState<T>,
53-
getValue: () => T,
54-
getPaused: () => boolean,
55-
update: (props: any) => AsyncResult<T>,
56-
stop: SpringStopFn<T>
55+
target: AnimationTarget<T>
5756
): AsyncResult<T> {
5857
if (props.cancel) {
59-
state.asyncTo = undefined
60-
return {
61-
value: getValue(),
62-
cancelled: true,
58+
// Stop the active `asyncTo` only on "default cancel".
59+
if (props.default) {
60+
state.asyncTo = undefined
6361
}
62+
return getCancelledResult(target)
6463
}
6564
if (props.pause) {
6665
await new Promise(next => {
@@ -92,17 +91,21 @@ export async function runAsync<T>(
9291
})
9392

9493
const { callId, onRest } = props
95-
96-
// Note: This function cannot be async, because `checkFailConditions` must be sync.
97-
const animate: any = (arg1: any, arg2?: any) => {
94+
const throwInvalidated = () => {
9895
// Prevent further animation if cancelled.
9996
if (callId <= (state.cancelId || 0)) {
100-
throw (result = { value: getValue(), cancelled: true })
97+
throw (result = getCancelledResult(target))
10198
}
10299
// Prevent further animation if another "runAsync" call is active.
103100
if (to !== state.asyncTo) {
104-
throw (result = { value: getValue(), finished: false })
101+
throw (result = getFinishedResult(target, false))
105102
}
103+
}
104+
105+
// Note: This function cannot use the `async` keyword, because we want the
106+
// `throw` statements to interrupt the caller.
107+
const animate: any = (arg1: any, arg2?: any) => {
108+
throwInvalidated()
106109

107110
const props: ControllerUpdate<T> = is.obj(arg1)
108111
? { ...arg1 }
@@ -115,12 +118,14 @@ export async function runAsync<T>(
115118
})
116119

117120
const parentTo = state.asyncTo
118-
return update(props).then(async result => {
121+
return target.start(props).then(async result => {
122+
throwInvalidated()
123+
119124
if (state.asyncTo == null) {
120125
state.asyncTo = parentTo
121126
}
122127

123-
if (getPaused()) {
128+
if (target.is('PAUSED')) {
124129
await new Promise(resolve => {
125130
state.unpause = concatFn(state.unpause, () => {
126131
state.unpause = void 0
@@ -142,12 +147,9 @@ export async function runAsync<T>(
142147
}
143148
// Async script
144149
else if (is.fun(to)) {
145-
await to(animate, stop)
146-
}
147-
result = {
148-
value: getValue(),
149-
finished: true,
150+
await to(animate, target.stop.bind(target) as any)
150151
}
152+
result = getFinishedResult(target, true)
151153
} catch (err) {
152154
if (err !== result) {
153155
throw err

0 commit comments

Comments
 (0)