@@ -92,27 +92,19 @@ export function runAsync<T extends AnimationTarget>(
9292 }
9393 }
9494
95+ // Safety cap for unterminating async scripts under `skipAnimation`.
96+ // Without animation frames to pace it, `while (true) await next(...)`
97+ // becomes a tight microtask loop that would hang the host.
98+ let skipAnimationCallCount = 0
99+ const SKIP_ANIMATION_CALL_LIMIT = 1024
100+
95101 const animate : any = ( arg1 : any , arg2 ?: any ) => {
96102 // Create the bail signal outside the returned promise,
97103 // so the generated stack trace is relevant.
98104 const bailSignal = new BailSignal ( )
99105 const skipAnimationSignal = new SkipAnimationSignal ( )
100106
101107 return ( async ( ) => {
102- if ( G . skipAnimation ) {
103- /**
104- * We need to stop animations if `skipAnimation`
105- * is set in the Globals
106- *
107- */
108- stopAsync ( state )
109-
110- // create the rejection error that's handled gracefully
111- skipAnimationSignal . result = getFinishedResult ( target , false )
112- bail ( skipAnimationSignal )
113- throw skipAnimationSignal
114- }
115-
116108 bailIfEnded ( bailSignal )
117109
118110 const props : any = is . obj ( arg1 ) ? { ...arg1 } : { ...arg2 , to : arg1 }
@@ -124,6 +116,21 @@ export function runAsync<T extends AnimationTarget>(
124116 }
125117 } )
126118
119+ if ( G . skipAnimation ) {
120+ if ( ++ skipAnimationCallCount > SKIP_ANIMATION_CALL_LIMIT ) {
121+ stopAsync ( state )
122+ skipAnimationSignal . result = getFinishedResult ( target , false )
123+ bail ( skipAnimationSignal )
124+ throw skipAnimationSignal
125+ }
126+
127+ // Apply each step immediately so the script can run to completion
128+ // and the spring lands on whatever value the final `next(...)` call
129+ // would set under normal animation.
130+ props . immediate = true
131+ return await target . start ( props )
132+ }
133+
127134 const result = await target . start ( props )
128135 bailIfEnded ( bailSignal )
129136
@@ -139,15 +146,6 @@ export function runAsync<T extends AnimationTarget>(
139146
140147 let result ! : AnimationResult < T >
141148
142- if ( G . skipAnimation ) {
143- /**
144- * We need to stop animations if `skipAnimation`
145- * is set in the Globals
146- */
147- stopAsync ( state )
148- return getFinishedResult ( target , false )
149- }
150-
151149 try {
152150 let animating ! : Promise < void >
153151
0 commit comments