Skip to content

Commit

Permalink
fix: base elapsed on subscription time
Browse files Browse the repository at this point in the history
And use performance.now() for the elapsed calculation instead of the
passed timestamp - see comment for explanation.
  • Loading branch information
cartant committed Jul 26, 2020
1 parent 655d3a1 commit d7c7c0b
Showing 1 changed file with 23 additions and 8 deletions.
31 changes: 23 additions & 8 deletions src/internal/observable/dom/animationFrames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export interface TimestampProvider {
* const source$ = animationFrames(customTSProvider);
*
* // Log increasing numbers 0...1...2... on every animation frame.
* source$.subscribe(({elapsed}) => console.log(elapsed));
* source$.subscribe(({ elapsed }) => console.log(elapsed));
* ```
*
* @param timestampProvider An object with a `now` method that provides a numeric timestamp
Expand All @@ -86,15 +86,30 @@ export function animationFrames(timestampProvider?: TimestampProvider) {
* @param timestampProvider The timestamp provider to use to create the observable
*/
function animationFramesFactory(timestampProvider?: TimestampProvider) {
return new Observable<{timestamp: number, elapsed: number}>(subscriber => {
return new Observable<{ timestamp: number, elapsed: number }>(subscriber => {
let id: number;
let start: DOMHighResTimeStamp | number | null = null;
// If no timestamp provider is specified, use performance.now() - as it
// will return timestamps 'compatible' with those passed to the run
// callback and won't be affected by NTP adjustments, etc.
const provider = timestampProvider || performance;
// Capture the start time upon subscription, as the run callback can remain
// queued for a considerable period of time and the elapsed time should
// represent the time elapsed since subscription - not the time since the
// first rendered animation frame.
const start = provider.now();
const run = (timestamp: DOMHighResTimeStamp | number) => {
const currentTimestamp = timestampProvider ? timestampProvider.now() : timestamp;
if (start === null) {
start = currentTimestamp;
}
subscriber.next({timestamp: currentTimestamp, elapsed: currentTimestamp - start});
// Use the provider's timestamp to calculate the elapsed time. Note that
// this means - if the caller hasn't passed a provider - that
// performance.now() will be used instead of the timestamp that was
// passed to the run callback. The reason for this is that the timestamp
// passed to the callback can be earlier than the start time, as it
// represents the time at which the browser decided it would render any
// queued frames - and that time can be earlier the captured start time.
const now = provider.now();
subscriber.next({
timestamp: timestampProvider ? now : timestamp,
elapsed: now - start
});
if (!subscriber.closed) {
id = requestAnimationFrame(run);
}
Expand Down

0 comments on commit d7c7c0b

Please sign in to comment.