(Everything discussed here is for React version 16.13.0)

While researching React’s “fiber” architecture, I came across some interesting things that I didn’t expect. One of these is the React scheduler. It, along with Fiber, is central to React’s ability to maintain a responsive UI when under heavy load (such as when animations are running, or when expensive calculations are repeatedly done).

So what is it, and how does it work?

From what I can tell, it’s a system allowing React to schedule tasks of different priorities onto Javascript’s single-threaded event loop.

Due to this single-threaded nature, only one thing at a time can run at a time in Javascript. Any code that React is running can block the browser from responding to user input, scrolling the page, or even updating the UI.

React’s scheduler handles this by allowing callbacks to be enqueued with different priorities. By allowing higher-priority callbacks to take precedence over lower-priority ones, it can do a better job of maintaining a responsive UI.

The only caveat to this is that it’s easy for high-priority work to constantly prevent other work from running (a problem known as starvation). To prevent this, each priority level has a timeout associated with it. After the timeout, the scheduler will go ahead and run the callback, even if there is higher priority work.

Priorities are defined in a file called SchedulerPriorities, believe it or not. They are:

Some examples of tasks with different priorities are:

Tasks are stored in a min-heap, ordered by their expiration time. This is the time the task was enqueued, plus the timeout of the task’s priority level. Once work is enqueued, the scheduler sets a timeout with its own callback. This in turn executes as many of the scheduled callbacks as it can, until control is yielded back to the browser.

Right now it looks like the scheduler decides to yield back to the browser every 5 milliseconds. However, there is some code to detect the presence of a proposed browser API called isInputPending (behind a feature flag), and use that if available.

And that’s the React scheduler. Let me know if I’ve got anything here wrong, or if anything isn’t as clear as it should be.