Skip to content

Commit

Permalink
Fix: Measure expiration times relative to module initialization (#15357)
Browse files Browse the repository at this point in the history
We use bitwise operations to compute expiration times, which means they
need to be smaller than 31 bits. So we measure times relative to module
initialization, similar to `performance.now`.

This was already working in the old fiber scheduler, but we didn't have
a test for it.
  • Loading branch information
acdlite authored and sebmarkbage committed Apr 9, 2019
1 parent b4bc33a commit 183d1f4
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
5 changes: 3 additions & 2 deletions packages/react-reconciler/src/ReactFiberScheduler.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,20 +228,21 @@ let interruptedBy: Fiber | null = null;
// In other words, because expiration times determine how updates are batched,
// we want all updates of like priority that occur within the same event to
// receive the same expiration time. Otherwise we get tearing.
let initialTimeMs: number = now();
let currentEventTime: ExpirationTime = NoWork;

export function requestCurrentTime() {
if (workPhase === RenderPhase || workPhase === CommitPhase) {
// We're inside React, so it's fine to read the actual time.
return msToExpirationTime(now());
return msToExpirationTime(now() - initialTimeMs);
}
// We're not inside React, so we may be in the middle of a browser event.
if (currentEventTime !== NoWork) {
// Use the same start time for all updates until we enter React again.
return currentEventTime;
}
// This is the first update since React yielded. Compute a new start time.
currentEventTime = msToExpirationTime(now());
currentEventTime = msToExpirationTime(now() - initialTimeMs);
return currentEventTime;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,31 @@ describe('ReactExpiration', () => {
'1 [D] [render]',
]);
});

it('should measure expiration times relative to module initialization', () => {
// Tests an implementation detail where expiration times are computed using
// bitwise operations.

jest.resetModules();
Scheduler = require('scheduler');
// Before importing the renderer, advance the current time by a number
// larger than the maximum allowed for bitwise operations.
const maxSigned31BitInt = 1073741823;
Scheduler.advanceTime(maxSigned31BitInt * 100);

// Now import the renderer. On module initialization, it will read the
// current time.
ReactNoop = require('react-noop-renderer');

ReactNoop.render('Hi');

// The update should not have expired yet.
expect(Scheduler).toFlushExpired([]);
expect(ReactNoop).toMatchRenderedOutput(null);

// Advance the time some more to expire the update.
Scheduler.advanceTime(10000);
expect(Scheduler).toFlushExpired([]);
expect(ReactNoop).toMatchRenderedOutput('Hi');
});
});

0 comments on commit 183d1f4

Please sign in to comment.