diff --git a/spec/schedulers/AnimationFrameScheduler-spec.ts b/spec/schedulers/AnimationFrameScheduler-spec.ts index eae794b1cb..1be5cf1e6b 100644 --- a/spec/schedulers/AnimationFrameScheduler-spec.ts +++ b/spec/schedulers/AnimationFrameScheduler-spec.ts @@ -141,6 +141,46 @@ describe('Scheduler.animationFrame', () => { } }); + it('should schedule next frame actions from a delayed one', (done) => { + animationFrame.schedule(() => { + animationFrame.schedule(() => { done(); }); + }, 1); + }); + + it('should schedule 2 actions for a subsequent frame', (done) => { + let runFirst = false; + animationFrame.schedule(() => { + animationFrame.schedule(() => { runFirst = true; }); + animationFrame.schedule(() => { + if (runFirst) { + done(); + } else { + done(new Error('First action did not run')); + } + }); + }); + }); + + it('should handle delayed action without affecting next frame actions', (done) => { + let runDelayed = false; + let runFirst = false; + animationFrame.schedule(() => { + animationFrame.schedule(() => { runFirst = true; }); + animationFrame.schedule(() => { + if (!runDelayed) { + done(new Error('Delayed action did not run')); + } else if (!runFirst) { + done(new Error('First action did not run')); + } else { + done(); + } + }); + + // This action will execute before the next frame because the delay is less than the one of the frame + animationFrame.schedule(() => { runDelayed = true; }, 1); + }); + }); + it('should not execute rescheduled actions when flushing', (done) => { let flushCount = 0; let scheduledIndices: number[] = []; diff --git a/spec/schedulers/AsapScheduler-spec.ts b/spec/schedulers/AsapScheduler-spec.ts index 5ec0401753..56a2ff7609 100644 --- a/spec/schedulers/AsapScheduler-spec.ts +++ b/spec/schedulers/AsapScheduler-spec.ts @@ -66,7 +66,7 @@ describe('Scheduler.asap', () => { const sandbox = sinon.createSandbox(); const fakeTimer = sandbox.useFakeTimers(); // callThrough is missing from the declarations installed by the typings tool in stable - const stubSetInterval = ( sandbox.stub(global, 'setInterval')).callThrough(); + const stubSetInterval = ( sandbox.stub(fakeTimer, 'setInterval')).callThrough(); const period = 50; const state = { index: 0, period }; type State = typeof state; @@ -92,7 +92,7 @@ describe('Scheduler.asap', () => { const sandbox = sinon.createSandbox(); const fakeTimer = sandbox.useFakeTimers(); // callThrough is missing from the declarations installed by the typings tool in stable - const stubSetInterval = ( sandbox.stub(global, 'setInterval')).callThrough(); + const stubSetInterval = ( sandbox.stub(fakeTimer, 'setInterval')).callThrough(); const period = 50; const state = { index: 0, period }; type State = typeof state; @@ -148,6 +148,12 @@ describe('Scheduler.asap', () => { }, 0, 0); }); + it('should schedule asap actions from a delayed one', (done) => { + asap.schedule(() => { + asap.schedule(() => { done(); }); + }, 1); + }); + it('should cancel the setImmediate if all scheduled actions unsubscribe before it executes', (done) => { let asapExec1 = false; let asapExec2 = false; diff --git a/src/internal/scheduler/AnimationFrameAction.ts b/src/internal/scheduler/AnimationFrameAction.ts index f9c8f8e39d..502bbc7f16 100644 --- a/src/internal/scheduler/AnimationFrameAction.ts +++ b/src/internal/scheduler/AnimationFrameAction.ts @@ -33,7 +33,7 @@ export class AnimationFrameAction extends AsyncAction { // cancel the requested animation frame and set the scheduled flag to // undefined so the next AnimationFrameAction will request its own. const { actions } = scheduler; - if (id != null && actions[actions.length - 1]?.id !== id) { + if (id != null && id === scheduler._scheduled && actions[actions.length - 1]?.id !== id) { animationFrameProvider.cancelAnimationFrame(id as number); scheduler._scheduled = undefined; } diff --git a/src/internal/scheduler/AnimationFrameScheduler.ts b/src/internal/scheduler/AnimationFrameScheduler.ts index 640afa2488..1f21ffa164 100644 --- a/src/internal/scheduler/AnimationFrameScheduler.ts +++ b/src/internal/scheduler/AnimationFrameScheduler.ts @@ -13,8 +13,13 @@ export class AnimationFrameScheduler extends AsyncScheduler { // are removed from the actions array and that can shift actions that are // scheduled to be executed in a subsequent flush into positions at which // they are executed within the current flush. - const flushId = this._scheduled; - this._scheduled = undefined; + let flushId; + if (action) { + flushId = action.id; + } else { + flushId = this._scheduled; + this._scheduled = undefined; + } const { actions } = this; let error: any;