Skip to content

Commit

Permalink
fix: don't execute actions scheduled within flush
Browse files Browse the repository at this point in the history
  • Loading branch information
cartant committed Nov 13, 2021
1 parent 67e2c83 commit fbaab9f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 8 deletions.
16 changes: 12 additions & 4 deletions src/internal/scheduler/AnimationFrameScheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,32 @@ import { AsyncScheduler } from './AsyncScheduler';
export class AnimationFrameScheduler extends AsyncScheduler {
public flush(action?: AsyncAction<any>): void {
this._active = true;
// The async id that effects a call to flush is stored in _scheduled.
// Before executing an action, it's necessary to check the action's async
// id to determine whether it's supposed to be executed in the current
// flush.
// Previous implementations of this method used a count to determine this,
// but that was unsound, as actions that are unsubscribed - i.e. cancelled -
// 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;

const { actions } = this;
let error: any;
let index = -1;
action = action || actions.shift()!;
const count = actions.length;

do {
if ((error = action.execute(action.state, action.delay))) {
break;
}
} while (++index < count && (action = actions.shift()));
} while ((action = actions[0]) && action.id === flushId && actions.shift());

this._active = false;

if (error) {
while (++index < count && (action = actions.shift())) {
while ((action = actions[0]) && action.id === flushId && actions.shift()) {
action.unsubscribe();
}
throw error;
Expand Down
16 changes: 12 additions & 4 deletions src/internal/scheduler/AsapScheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,32 @@ import { AsyncScheduler } from './AsyncScheduler';
export class AsapScheduler extends AsyncScheduler {
public flush(action?: AsyncAction<any>): void {
this._active = true;
// The async id that effects a call to flush is stored in _scheduled.
// Before executing an action, it's necessary to check the action's async
// id to determine whether it's supposed to be executed in the current
// flush.
// Previous implementations of this method used a count to determine this,
// but that was unsound, as actions that are unsubscribed - i.e. cancelled -
// 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;

const { actions } = this;
let error: any;
let index = -1;
action = action || actions.shift()!;
const count = actions.length;

do {
if ((error = action.execute(action.state, action.delay))) {
break;
}
} while (++index < count && (action = actions.shift()));
} while ((action = actions[0]) && action.id === flushId && actions.shift());

this._active = false;

if (error) {
while (++index < count && (action = actions.shift())) {
while ((action = actions[0]) && action.id === flushId && actions.shift()) {
action.unsubscribe();
}
throw error;
Expand Down

0 comments on commit fbaab9f

Please sign in to comment.