Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Fix: Measure expiration times relative to module initialization
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 committed Apr 9, 2019
commit f95b8fdb7b74b2b2efe9139192fc6127ace35352
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');
});
});