Performance
React Conf 2017 (~3/2017) (React v16 release = 9/2017)
Day 1
Keynote
Part 1 (~6min): Tom Occhino
Part 2 (~14min): Jing Chen - Incrementally Adopting RN at Facebook
Part 3 (~18min): Sebastian Markbage - React Performance End to End (React Fiber)
Enhancing performance:
CSR & SSR = best (not an all or none approach -- CSR/SPA popular at the time)
Briefly mentions the benefit of a React compiler
Mentions streaming
Concept of rendering "priority levels" (low/high)
...aka, "scheduling is a core primitive of UI engineering"
at the time:
very ad hoc solutions for this (threads, workers, built-in primitives), all with their own benefits/tradeoffs
final solution:
"React Fiber" (React v16)
complete reimplementation of the core algorithm inside React (with ground-up support for built-in scheduling)
"A New Foundation"
(Lin Clark has a talk about how it works under-the-hood)
built with full backwards compatibility
launched in "compatibility mode" by default (with an opt-in for asynchronous interruptible rendering -- "asynchronous mode")
future versions = "asynchronous mode" by default
Part 4 (~6min): Tom Occhino - React Fiber, Create React App (CRA), React Community
<ErrorBoundary />
(failing in an isolated way, and handle gracefully; wrap components)
Ability to return multiple components from "render"
(can return arrays & strings now)
React Fiber = entirely written in Flow
(easier to follow core React code, make contributions, etc.)
CRA introduction
(CLI for spinning up a react app --
create-react-app
)
(~30min) Lin Clark - A Cartoon Intro to Fiber
Fiber (Fiber reconciler)
improves perceived performance & responsiveness to React apps
= new reconciliation algorithm
History
React's "main thing" when it came out = vDOM
made coding UI much easier
instead of telling browser how to go from current version to next version, just tell React what next version should look like
(makes UI easier for not just DOM, but all platforms -- native apps, VR, hardware, ...)
Reconciler vs Render
renderer = pluggable
(can use any from community to target host platforms besides DOM)
reconciler = only one (React's)
High vs Low priority updates (Fiber handles this)
Note:
for fluid motion/UI updates, need 60fps (16ms per frame)
React updating is fast enough to do this, but often "larger update" user code ends up coming in and blocking it (mostly due to render function & other user code functions)
"updates" = React updates, browser updates (CSS animations, browser resizes)... all would get trapped behind "larger updates", due to all being on a single/main thread
Solution = make updates "play together" better (high/low priority updates)
With Fiber, React knows how to "work better" with the main thread
minimizes & batches DOM changes
how to split up work, how to prioritize work
watch (keep track of how much time has passed)
Reconciliation
Elements, Instances, Dom
Old reconciler ("stack reconciler"; retroactively given a name):
one after the other ("layer by layer") (create Element > update Instance > update DOM node)
recursively calls updateComponent or mountComponent until gets to bottom of tree
as it's walking down the tree and changing Instances, it's changing the corresponding DOM nodes
New reconciler ("fiber reconciler"):
in batches (compute a little part of the tree, then come back up to see if it has other work to do)
"fiber" data structure = how main thread keeps track of where it is in the tree
plain JS object
{ stateNode, child, return, sibling, ... }
1:1 relationship with an Instance (
{ stateNode }
)
"phases"
(1) Phase 1 (render / reconciliation)
builds up
workInProgress
tree(figures out changes via this tree, but doesn't actually make the corresponding DOM node updates -- unlike the stack reconciler)
can be interrupted
(2) Phase 2 (commit)
cannot be interrupted (all at once)
(prevents UI inconsistencies -- e.g. browser deciding it needs to update)
Component
Set state is called (clicked button)
React adds update to update queue for component
React schedules the work (via
requestIdleCallback
)Whenever main thread has some free time (e.g. done with browser updates; no frames scheduled in the near future), it comes back to React, and start building up
workInProgress
tree (viaworkLoop
function)workLoop:
next unit of work
time remaining (that it has with main thread)
...clone > mark as update or not (+/- need change in DOM) > create elements > ... > (shouldComponentUpdate / props / memoized?) > ... (~16-19min)
...
effect list = list of changes (+ need change in DOM)
...
requestIdleCallback = used when more work is to be done, but main thread needs to stay busy with browser updates
browser updates = callbacks (i.e. JS event loop) (may include "layout" callback, ...)
Day 2
...
React docs (old):
(1) Trigger,... (2) Render, (3) Commit,... (4) Painting ("browser rendering")
React only changes the DOM notes if there is a difference between renders
(i.e. the component itself may rerender, but it won't update all the DOM notes represented within the return JSX -- only the ones that have changed)
Last updated