Skip to content

Commit ad36f57

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

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

spec/schedulers/AnimationFrameScheduler-spec.ts

Lines changed: 24 additions & 1 deletion
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,27 @@ 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+
expect(result).to.deep.equal(['work']);
254+
reschedule = false;
255+
} else {
256+
expect(result).to.deep.equal(['work', 'task 1', 'task 2', 'work']);
257+
sandbox.restore();
258+
done();
259+
}
260+
}
261+
animationFrameScheduler.schedule(work);
262+
expect(result).to.deep.equal([]);
263+
});
241264
});

spec/schedulers/AsapScheduler-spec.ts

Lines changed: 24 additions & 1 deletion
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,27 @@ 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+
expect(result).to.deep.equal(['work']);
304+
reschedule = false;
305+
} else {
306+
expect(result).to.deep.equal(['work', 'task 1', 'task 2', 'work']);
307+
sandbox.restore();
308+
done();
309+
}
310+
}
311+
asapScheduler.schedule(work);
312+
expect(result).to.deep.equal([]);
313+
});
291314
});

src/internal/scheduler/AnimationFrameAction.ts

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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)