forked from ReactiveX/rxjs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(schedulers): fix asap and animationFrame schedulers to execute ac…
…ross async boundaries. The AsapScheduler and AnimationFrameSchedulers were totally busted. My bad. Now they execute their scheduled actions in batches. If actions reschedule while executing a batch, a new frame is requested for the rescheduled action to execute in. This PR also simplifies the public `Scheduler` and `Action` APIs. Implementation details like the `actions` queue and `active` boolean are now on the concrete implementations, so it's easier for people to implement the Scheduler API. This PR also renames `FutureAction` -> `AsyncAction` to conform to the same naming convention as the rest of the Action types. Fixes ReactiveX#1814
- Loading branch information
Showing
31 changed files
with
638 additions
and
602 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import {expect} from 'chai'; | ||
import * as Rx from '../../dist/cjs/Rx'; | ||
|
||
const Scheduler = Rx.Scheduler; | ||
const queue = Scheduler.queue; | ||
|
||
/** @test {Scheduler} */ | ||
describe('Scheduler.queue', () => { | ||
it('should switch from synchronous to asynchronous at will', (done: MochaDone) => { | ||
let lastExecTime = 0; | ||
let asyncExec = false; | ||
queue.schedule(function (index) { | ||
if (index === 0) { | ||
lastExecTime = queue.now(); | ||
this.schedule(1, 100); | ||
} else if (index === 1) { | ||
if (queue.now() - lastExecTime < 100) { | ||
done(new Error('Execution happened synchronously.')); | ||
} else { | ||
asyncExec = true; | ||
lastExecTime = queue.now(); | ||
this.schedule(2, 0); | ||
} | ||
} else if (index === 2) { | ||
if (asyncExec === false) { | ||
done(new Error('Execution happened synchronously.')); | ||
} else { | ||
done(); | ||
} | ||
} | ||
}, 0, 0); | ||
asyncExec = false; | ||
}); | ||
it('should unsubscribe the rest of the scheduled actions if an action throws an error', () => { | ||
const actions = []; | ||
let action2Exec = false; | ||
let action3Exec = false; | ||
let errorValue = undefined; | ||
try { | ||
queue.schedule(() => { | ||
actions.push( | ||
queue.schedule(() => { throw new Error('oops'); }), | ||
queue.schedule(() => { action2Exec = true; }), | ||
queue.schedule(() => { action3Exec = true; }) | ||
); | ||
}); | ||
} catch (e) { | ||
errorValue = e; | ||
} | ||
expect(actions.every((action) => action.isUnsubscribed)).to.be.true; | ||
expect(action2Exec).to.be.false; | ||
expect(action3Exec).to.be.false; | ||
expect(errorValue).exist; | ||
expect(errorValue.message).to.equal('oops'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,59 @@ | ||
import {Subscription} from './Subscription'; | ||
import {Action} from './scheduler/Action'; | ||
import {Subscription} from './Subscription'; | ||
|
||
/** | ||
* An execution context and a data structure to order tasks and schedule their | ||
* execution. Provides a notion of (potentially virtual) time, through the | ||
* `now()` getter method. | ||
* | ||
* Each unit of work in a Scheduler is called an {@link Action}. | ||
* | ||
* ```ts | ||
* class Scheduler { | ||
* now(): number; | ||
* schedule(work, delay?, state?): Subscription; | ||
* } | ||
* ``` | ||
* | ||
* @class Scheduler | ||
*/ | ||
export class Scheduler { | ||
|
||
public static now: () => number = Date.now ? Date.now : () => +new Date(); | ||
|
||
constructor(private SchedulerAction: typeof Action, | ||
now: () => number = Scheduler.now) { | ||
this.now = now; | ||
} | ||
|
||
/** | ||
* A getter method that returns a number representing the current time | ||
* (at the time this function was called) according to the scheduler's own | ||
* internal clock. | ||
* @return {number} A number that represents the current time. May or may not | ||
* have a relation to wall-clock time. May or may not refer to a time unit | ||
* (e.g. milliseconds). | ||
*/ | ||
public now: () => number; | ||
|
||
export interface Scheduler { | ||
now(): number; | ||
schedule<T>(work: (state?: T) => Subscription | void, delay?: number, state?: T): Subscription; | ||
flush(): void; | ||
active: boolean; | ||
actions: Action<any>[]; // XXX: use `any` to remove type param `T` from `Scheduler`. | ||
scheduledId: number; | ||
/** | ||
* Schedules a function, `work`, for execution. May happen at some point in | ||
* the future, according to the `delay` parameter, if specified. May be passed | ||
* some context object, `state`, which will be passed to the `work` function. | ||
* | ||
* The given arguments will be processed an stored as an Action object in a | ||
* queue of actions. | ||
* | ||
* @param {function(state: ?T): ?Subscription} work A function representing a | ||
* task, or some unit of work to be executed by the Scheduler. | ||
* @param {number} [delay] Time to wait before executing the work, where the | ||
* time unit is implicit and defined by the Scheduler itself. | ||
* @param {T} [state] Some contextual data that the `work` function uses when | ||
* called by the Scheduler. | ||
* @return {Subscription} A subscription in order to be able to unsubscribe | ||
* the scheduled work. | ||
*/ | ||
public schedule<T>(work: (state?: T) => void, delay: number = 0, state?: T): Subscription { | ||
return new this.SchedulerAction<T>(this, work).schedule(state, delay); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.