Skip to content

Commit

Permalink
[Scheduler] Store Tasks on a Min Binary Heap (#16245)
Browse files Browse the repository at this point in the history
* [Scheduler] Store Tasks on a Min Binary Heap

Switches Scheduler's priority queue implementation (for both tasks and
timers) to an array-based min binary heap.

This replaces the naive linked-list implementation that was left over
from the queue we once used to schedule React roots. A list was arguably
fine when it was only used for roots, since the total number of roots is
usually small, and is only 1 in the common case of a single-page app.

Since Scheduler is now used for many types of JavaScript tasks (e.g.
including timers), the total number of tasks can be much larger.

Binary heaps are the standard way to implement priority queues.
Insertion is O(1) in the average case (append to the end) and O(log n)
in the worst. Deletion is O(log n). Peek is O(1).

* Sophie nits
  • Loading branch information
acdlite committed Aug 8, 2019
1 parent 95767ac commit d77c623
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 242 deletions.
18 changes: 3 additions & 15 deletions packages/react-dom/src/__tests__/ReactUpdates-test.js
Expand Up @@ -1631,6 +1631,7 @@ describe('ReactUpdates', () => {
ReactDOM.render(<App />, container);
while (error === null) {
Scheduler.unstable_flushNumberOfYields(1);
Scheduler.unstable_clearYields();
}
expect(error).toContain('Warning: Maximum update depth exceeded.');
expect(stack).toContain('in NonTerminating');
Expand All @@ -1653,34 +1654,21 @@ describe('ReactUpdates', () => {
React.useEffect(() => {
if (step < LIMIT) {
setStep(x => x + 1);
Scheduler.unstable_yieldValue(step);
}
});
Scheduler.unstable_yieldValue(step);
return step;
}

const container = document.createElement('div');
act(() => {
ReactDOM.render(<Terminating />, container);
});

// Verify we can flush them asynchronously without warning
for (let i = 0; i < LIMIT * 2; i++) {
Scheduler.unstable_flushNumberOfYields(1);
}
expect(container.textContent).toBe('50');

// Verify restarting from 0 doesn't cross the limit
act(() => {
_setStep(0);
// flush once to update the dom
Scheduler.unstable_flushNumberOfYields(1);
expect(container.textContent).toBe('0');
for (let i = 0; i < LIMIT * 2; i++) {
Scheduler.unstable_flushNumberOfYields(1);
}
expect(container.textContent).toBe('50');
});
expect(container.textContent).toBe('50');
});

it('can have many updates inside useEffect without triggering a warning', () => {
Expand Down

0 comments on commit d77c623

Please sign in to comment.