React Fiber
Frances Ng - Datarama
Hawker center
Chicken rice queue
2
1
3
4
5
6
7
8
9
10
2
1
3
4
5
6
.
.
.
.
Uncle and Auntie
Hawker center
New System of QUEUE
2
1
3
4
5
6
7
8
9
10
- Split up the Tasks better.
- Take Higher Priority work like a `Special Order` first even if the other task has been started
- After Uncle finishes a unit of work, tell him how much time left, assign him with next tasks.
Uncle and Auntie
Uncle
Auntie
Prepare order
ReconCilIation
+
Rendering
DOM
Native iOS View
Android View
Fiber
Stack reconciler
Subtitle

mountComponent()
mountComponent()
mountComponent()
mountComponent()
mountComponent()
mountComponent()
fiber
fiber - A Unit of Work
Create smoother UI experiences
New stuff
priority updates
Cooperative scheduling
INCREMENTAL rendering
reuse work
Scheduling
beginWork
completeWork
commitWork
1
2
1
1
1
2
current fiber
child fiber
child
return
child fiber
child
sibling
return
work in progress fiber
Effect List
1
Interruptible
Urgent work can jump queue
requestIdleCallback / requestAnimationFrame
Priorities/ExpirationTime
Unit: 1 fiber
Get diff
markUpdate
effectTag
alternate
return
requestIdleCallback(callback)
IdleDeadline
- IdleDeadline.timeRemaining()
If still got time, do next
If not enough time, pass to next schedule
v16.0
by Priority Level
v16.1+
by Expiration Time
- The earlier Expiration Time, the higher priority
var ReactPriorityLevel = {
NoWork: 0, // No work is pending.
SynchronousPriority: 1, // For controlled text inputs. Synchronous side-effects.
TaskPriority: 2, // Completes at the end of the current tick.
HighPriority: 3, // Interaction that needs to complete pretty soon to feel responsive.
LowPriority: 4, // Data fetching, or result from updating stores.
OffscreenPriority: 5 };
function beginWork(current, workInProgress, renderExpirationTime) {
if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) {
return bailoutOnLowPriority(current, workInProgress);
}
switch (workInProgress.tag) {
case IndeterminateComponent:
return mountIndeterminateComponent(current, workInProgress, renderExpirationTime);
case FunctionalComponent:
return updateFunctionalComponent(current, workInProgress);
case ClassComponent:
return updateClassComponent(current, workInProgress, renderExpirationTime);
case HostRoot:
return updateHostRoot(current, workInProgress, renderExpirationTime);
case HostComponent:
return updateHostComponent(current, workInProgress, renderExpirationTime);
case HostText:
return updateHostText(current, workInProgress);
case CallHandlerPhase:
// This is a restart. Reset the tag to the initial phase.
workInProgress.tag = CallComponent;
// Intentionally fall through since this is now the same.
case CallComponent:
return updateCallComponent(current, workInProgress, renderExpirationTime);
case ReturnComponent:
// A return component is just a placeholder, we can just run through the
// next one immediately.
return null;
case HostPortal:
return updatePortalComponent(current, workInProgress, renderExpirationTime);
case Fragment:
return updateFragment(current, workInProgress);
default:
invariant_1$1(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');
}
}
react/packages/react-reconciler/src/ReactFiberExpirationTime.js
export const NoWork = 0;
export const Sync = 1;
export const Never = MAX_SIGNED_31_BIT_INT;
const UNIT_SIZE = 10;
const MAGIC_NUMBER_OFFSET = 2;
// 1 unit of expiration time represents 10ms.
export function msToExpirationTime(ms: number): ExpirationTime {
// Always add an offset so that we don't clash with the magic number for NoWork.
return ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET;
}
function beginWork(current, workInProgress, priorityLevel) {
if (workInProgress.pendingWorkPriority === NoWork$3 || workInProgress.pendingWorkPriority > priorityLevel) {
return bailoutOnLowPriority(current, workInProgress);
}
{
ReactDebugCurrentFiber$4.setCurrentFiber(workInProgress, null);
}
switch (workInProgress.tag) {
case IndeterminateComponent$2:
return mountIndeterminateComponent(current, workInProgress, priorityLevel);
case FunctionalComponent$1:
return updateFunctionalComponent(current, workInProgress);
case ClassComponent$6:
return updateClassComponent(current, workInProgress, priorityLevel);
case HostRoot$7:
return updateHostRoot(current, workInProgress, priorityLevel);
case HostComponent$7:
return updateHostComponent(current, workInProgress, priorityLevel);
case HostText$4:
return updateHostText(current, workInProgress);
case CoroutineHandlerPhase:
// This is a restart. Reset the tag to the initial phase.
workInProgress.tag = CoroutineComponent$1;
// Intentionally fall through since this is now the same.
case CoroutineComponent$1:
return updateCoroutineComponent(current, workInProgress);
case YieldComponent$2:
// A yield component is just a placeholder, we can just run through the
// next one immediately.
return null;
case HostPortal$4:
return updatePortalComponent(current, workInProgress);
case Fragment$2:
return updateFragment(current, workInProgress);
default:
invariant_1(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');
}
}
https://fiber-debugger.surge.sh/
2
Non-Interruptible
Reflect Effect List and Commit to Host
After all scheduled fibers completed in this frame
componentDidMount
componentDidUpdate
componentWillUnmount
Only
How
does/did/will
it affect us
Generally, Nothing atm
v16.*
By default, AsyncScheduling is turned off.
Everything in Sync Scheduling.
If AsyncScheduling is on by default, existing apps' logics might have to change regarding the component lifeCycles triggers
v17 ???
Good read
React Fiber - Jan 2018
By Frances Ng
React Fiber - Jan 2018
- 934