Skip to content

Commit 4319c90

Browse files
committed
fix: animationFrameScheduler and asapScheduler no longer executing actions
Fixes #6854
1 parent ef416f0 commit 4319c90

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

spec/schedulers/AnimationFrameScheduler-spec.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { expect } from 'chai';
22
import * as sinon from 'sinon';
3-
import { animationFrameScheduler, Subscription, merge } from 'rxjs';
3+
import {animationFrameScheduler, Subscription, merge, SchedulerAction} from 'rxjs';
44
import { delay } from 'rxjs/operators';
55
import { TestScheduler } from 'rxjs/testing';
66
import { observableMatcher } from '../helpers/observableMatcher';
@@ -238,4 +238,25 @@ describe('Scheduler.animationFrame', () => {
238238
done();
239239
});
240240
});
241+
242+
it('should handle actions scheduled during flush before current action is rescheduled', (done) => {
243+
const sandbox = sinon.createSandbox();
244+
245+
const result: string[] = [];
246+
let reschedule = true;
247+
function work(this: SchedulerAction<unknown>) {
248+
result.push('work');
249+
if (reschedule) {
250+
animationFrameScheduler.schedule(() => result.push('task 1'));
251+
animationFrameScheduler.schedule(() => result.push('task 2'));
252+
this.schedule();
253+
reschedule = false;
254+
} else {
255+
expect(result).to.deep.equal(['work', 'task 1', 'task 2', 'work']);
256+
sandbox.restore();
257+
done();
258+
}
259+
}
260+
animationFrameScheduler.schedule(work);
261+
});
241262
});

spec/schedulers/AsapScheduler-spec.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { expect } from 'chai';
22
import * as sinon from 'sinon';
3-
import { asapScheduler, Subscription, SchedulerAction, merge } from 'rxjs';
3+
import {asapScheduler, Subscription, SchedulerAction, merge, animationFrameScheduler} from 'rxjs';
44
import { delay } from 'rxjs/operators';
55
import { TestScheduler } from 'rxjs/testing';
66
import { observableMatcher } from '../helpers/observableMatcher';
@@ -288,4 +288,25 @@ describe('Scheduler.asap', () => {
288288
done();
289289
});
290290
});
291+
292+
it('should handle actions scheduled during flush before current action is rescheduled', (done) => {
293+
const sandbox = sinon.createSandbox();
294+
295+
const result: string[] = [];
296+
let reschedule = true;
297+
function work(this: SchedulerAction<unknown>) {
298+
result.push('work');
299+
if (reschedule) {
300+
asapScheduler.schedule(() => result.push('task 1'));
301+
asapScheduler.schedule(() => result.push('task 2'));
302+
this.schedule();
303+
reschedule = false;
304+
} else {
305+
expect(result).to.deep.equal(['work', 'task 1', 'task 2', 'work']);
306+
sandbox.restore();
307+
done();
308+
}
309+
}
310+
asapScheduler.schedule(work);
311+
});
291312
});

src/internal/scheduler/AnimationFrameAction.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ export class AnimationFrameAction<T> extends AsyncAction<T> {
2727
if ((delay != null && delay > 0) || (delay == null && this.delay > 0)) {
2828
return super.recycleAsyncId(scheduler, id, delay);
2929
}
30-
// If the scheduler queue has no remaining actions with the same async id,
30+
// If the scheduler queue has no remaining actions for the next schedule,
3131
// cancel the requested animation frame and set the scheduled flag to
3232
// undefined so the next AnimationFrameAction will request its own.
33-
if (!scheduler.actions.some((action) => action.id === id)) {
33+
if (scheduler._scheduled === id && !scheduler.actions.some((action) => action.id === id)) {
3434
animationFrameProvider.cancelAnimationFrame(id);
3535
scheduler._scheduled = undefined;
3636
}

src/internal/scheduler/AsapAction.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ export class AsapAction<T> extends AsyncAction<T> {
2727
if ((delay != null && delay > 0) || (delay == null && this.delay > 0)) {
2828
return super.recycleAsyncId(scheduler, id, delay);
2929
}
30-
// If the scheduler queue has no remaining actions with the same async id,
30+
// If the scheduler queue has no remaining actions for the next schedule,
3131
// cancel the requested microtask and set the scheduled flag to undefined
3232
// so the next AsapAction will request its own.
33-
if (!scheduler.actions.some((action) => action.id === id)) {
33+
if (scheduler._scheduled === id && !scheduler.actions.some((action) => action.id === id)) {
3434
immediateProvider.clearImmediate(id);
3535
scheduler._scheduled = undefined;
3636
}

0 commit comments

Comments
 (0)