↝ FIBER ARCHITECTURE ⇢ REACT-SPECIFIC
IMPLEMENTATION OF A CALL-STACK-LIKE MODEL
WHERE REACT HAS FULL CONTROL OF SCHEDULING
WHAT SHOULD BE DONE
↝ FIBER ⇢ A STACK FRAME FOR A REACT COMPONENT
Slide 17
Slide 17 text
Fibers as
Units of Work
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 18
Slide 18 text
DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT
RETURNED FROM THE RENDER METHOD IS MERGED INTO THE
TREE OF FIBER NODES.
DEPENDING ON THE TYPE OF A REACT ELEMENT THE
FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES.
EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT
DESCRIBES THE WORK THAT NEEDS TO BE DONE.
ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END
UP WITH A BUNCH OF REACT ELEMENTS.
Slide 19
Slide 19 text
DURING RECONCILIATION, DATA FROM EVERY REACT
ELEMENT RETURNED FROM THE RENDER METHOD IS
MERGED INTO THE TREE OF FIBER NODES.
DEPENDING ON THE TYPE OF A REACT ELEMENT THE
FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES.
EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT
DESCRIBES THE WORK THAT NEEDS TO BE DONE.
ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END
UP WITH A BUNCH OF REACT ELEMENTS.
Slide 20
Slide 20 text
DEPENDING ON THE TYPE OF A REACT ELEMENT THE
FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES.
EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT
DESCRIBES THE WORK THAT NEEDS TO BE DONE.
ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END
UP WITH A BUNCH OF REACT ELEMENTS.
DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT
RETURNED FROM THE RENDER METHOD IS MERGED INTO THE
TREE OF FIBER NODES.
Slide 21
Slide 21 text
EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT
DESCRIBES THE WORK THAT NEEDS TO BE DONE.
ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END
UP WITH A BUNCH OF REACT ELEMENTS.
DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT
RETURNED FROM THE RENDER METHOD IS MERGED INTO THE
TREE OF FIBER NODES.
DEPENDING ON THE TYPE OF A REACT ELEMENT THE
FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES.
Slide 22
Slide 22 text
ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END
UP WITH A BUNCH OF REACT ELEMENTS.
DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT
RETURNED FROM THE RENDER METHOD IS MERGED INTO THE
TREE OF FIBER NODES.
DEPENDING ON THE TYPE OF A REACT ELEMENT THE
FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES.
A UNIT OF WORK.
EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT
DESCRIBES THE WORK THAT NEEDS TO BE DONE.
Slide 23
Slide 23 text
ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END
UP WITH A BUNCH OF REACT ELEMENTS.
DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT
RETURNED FROM THE RENDER METHOD IS MERGED INTO THE
TREE OF FIBER NODES.
DEPENDING ON THE TYPE OF A REACT ELEMENT THE
FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES.
A UNIT OF WORK.
EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT
DESCRIBES THE WORK THAT NEEDS TO BE DONE.
AND THAT MAKES IT A
CONVENIENT WAY TO TRACK,
SCHEDULE, PAUSE AND
ABORT THE WORK.
Slide 24
Slide 24 text
Visualizing
Units of Work
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 25
Slide 25 text
🤓💻
EXPERIMENT #1
INSPECTING ELEMENTS
Slide 26
Slide 26 text
No content
Slide 27
Slide 27 text
No content
Slide 28
Slide 28 text
let fiberNode
=
fiberRoot.current;
let fibersMap
=
new Map();
while (fiberNode) {
if (fiberNode.stateNode
!
=
=
null) {
fibersMap.set(fiberNode.stateNode, fiberNode);
}
if (fiberNode.child === null) {
while (fiberNode
!
=
=
null
&
&
fiberNode.sibling === null) {
fiberNode
=
fiberNode.return;
}
fiberNode
=
fiberNode?.sibling;
continue;
}
fiberNode
=
fiberNode.child;
}
Slide 29
Slide 29 text
let fiberNode
=
fiberRoot.current;
let fibersMap
=
new Map();
while (fiberNode) {
if (fiberNode.stateNode
!
=
=
null) {
fibersMap.set(fiberNode.stateNode, fiberNode);
}
if (fiberNode.child === null) {
while (fiberNode
!
=
=
null
&
&
fiberNode.sibling === null) {
fiberNode
=
fiberNode.return;
}
fiberNode
=
fiberNode?.sibling;
continue;
}
fiberNode
=
fiberNode.child;
}
🤯
Manipulating
Units of Work
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 34
Slide 34 text
🙋✋
QUESTION #1
HAVE YOU EVER HEARD ABOUT HOMOICONICITY?
Slide 35
Slide 35 text
(let [x 1]
(inc x)) ;
=
>
2
Slide 36
Slide 36 text
PERFORMS A TEMPORARY BINDING
(BINDS X TO THE VALUE 1)
(let [x 1]
(inc x)) ;
=
>
2
Slide 37
Slide 37 text
INCREMENTS X TO GIVE THE
RETURN VALUE OF 2
(let [x 1]
(inc x)) ;
=
>
2
Slide 38
Slide 38 text
IT CAN BE THOUGHT OF AS A LIST WITH THREE ELEMENTS
↝ A SYMBOL NAMED LET
↝ A VECTOR WITH TWO ELEMENTS
↝ A SYMBOL NAMED X
↝ AND AN INTEGER
↝ A LIST WITH TWO ELEMENTS
↝ A SYMBOL NAMED INC
↝ AND A SYMBOL NAMED X
Slide 39
Slide 39 text
“…HOMOICONICITY IS A PROPERTY OF SOME
PROGRAMMING LANGUAGES IN WHICH THE CODE USED TO
EXPRESS A PROGRAM IS WRITTEN USING THE DATA
STRUCTURES OF THAT LANGUAGE.
🤯
Slide 40
Slide 40 text
CODE = DATA
“…HOMOICONICITY IS A PROPERTY OF SOME
PROGRAMMING LANGUAGES IN WHICH THE CODE
USED TO EXPRESS A PROGRAM IS WRITTEN USING
THE DATA STRUCTURES OF THAT LANGUAGE.
🤯
Slide 41
Slide 41 text
↝ REACT ELEMENTS ARE JUST DATA
↝ JUST LIKE IN LISP, REACT COMPONENTS CAN
MANIPULATE THEIR CHILDREN AND RETURN
COMPLETELY DIFFERENT THINGS
const supportsSensor
=
()
=
>
Boolean(window.AmbientLightSensor);
const AmbientLight
=
React.lazy(()
=
>
import("./AmbientLight"));
const Fallback
=
React.lazy(()
=
>
import("./Fallback"));
export default function MyComponent() {
const { Match, When, Otherwise }
=
usePatternMatch();
return (
);
}
PATTERN MATCHING
+ REACT.SUSPENSE
+ REACT.LAZY()
= USERS DOWNLOAD ONLY THE
ACTUAL COMPONENT BUNDLE
THAT MATCHES A CONDITION
Slide 47
Slide 47 text
const supportsSensor
=
()
=
>
Boolean(window.AmbientLightSensor);
const AmbientLight
=
React.lazy(()
=
>
import("./AmbientLight"));
const Fallback
=
React.lazy(()
=
>
import("./Fallback"));
export default function MyComponent() {
const { Match, When, Otherwise }
=
usePatternMatch();
return (
);
}
PATTERN MATCHING
+ REACT.SUSPENSE
+ REACT.LAZY()
= USERS DOWNLOAD ONLY THE
ACTUAL COMPONENT BUNDLE
THAT MATCHES A CONDITION
MANIPULATING BASED ON
ELEMENTS DATA.
Slide 48
Slide 48 text
HTTPS://GITHUB.COM/
YTHECOMBINATOR/REACT-MATCHEZ
Slide 49
Slide 49 text
Coroutines
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 50
Slide 50 text
No content
Slide 51
Slide 51 text
1. A GENERATOR (PRODUCER) THAT
CAN ALSO CONSUME VALUES.
Slide 52
Slide 52 text
1.
A GENERATOR (PRODUCER) THAT
CAN ALSO CONSUME VALUES.
↝ JAVASCRIPT GENERATORS CAN
CONSUME VALUES
↝ BY THIS DEFINITION, THEY ARE
COROUTINES
Slide 53
Slide 53 text
2. A GENERATOR THAT CAN RESOLVE
ASYNCHRONOUS VALUES, LIKE
ASYNC/AWAIT.
Slide 54
Slide 54 text
2. ↝ THIS IS THE MOST COMMON
MEANING OF “COROUTINE” IN
THE JAVASCRIPT WORLD
↝ WE HAD CO AND BLUEBIRD,
WHICH HAD ASYNC/AWAIT
IMPLEMENTATIONS BASED ON
GENERATORS
A GENERATOR THAT CAN RESOLVE
ASYNCHRONOUS VALUES, LIKE
ASYNC/AWAIT.
Slide 55
Slide 55 text
3. A GENERATOR THAT CAN YIELD
WITH A STACKFUL CONTINUATION
Slide 56
Slide 56 text
3. ↝ = DEEP AWAIT
↝ WITH SUSPENSE, WE CAN
PAUSE RECONCILIATION AT ANY
DEPTH
A GENERATOR THAT CAN YIELD
WITH A STACKFUL CONTINUATION
🤯
Slide 57
Slide 57 text
Fibers
CONTROL IS PASSED TO A
SCHEDULER WHICH DETERMINES
WHAT TO RUN NEXT
↝ = CONTROLLED AT THE LEVEL OF THE
OPERATING SYSTEM OR FRAMEWORK
↝ E.G. NODE.JS EVENT LOOP
Slide 58
Slide 58 text
Coroutines
CONTROL IS PASSED TO THE CALLER
AND HANDLED BY APPLICATION
CODE
Fibers
CONTROL IS PASSED TO A
SCHEDULER WHICH DETERMINES
WHAT TO RUN NEXT
Slide 59
Slide 59 text
Coroutines &
React
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 60
Slide 60 text
COROUTINES APPEARED WHEN WORK ON FIBER WAS FIRST
GOING AS A SPECIFIC COMPONENT TYPE.
THE IDEA BEHIND COROUTINES — AS
OPPOSED TO FIBERS — WAS TO GIVE
COMPONENTS EXPLICIT CONTROL OVER
YIELDING AND RESUMPTION.
Slide 61
Slide 61 text
HTTPS://GITHUB.COM/FACEBOOK/REACT/
PULL/6859
Slide 62
Slide 62 text
↝ COROUTINES PER SI IN REACT NO LONGER EXIST.
↝ IT WILL BE FASCINATING TO SEE WHAT FORM
COROUTINES TAKE WHEN THEY RETURN TO REACT FIBER.
Slide 63
Slide 63 text
Coroutines &
Concurrent
React
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 64
Slide 64 text
HTTPS://WWW.YOUTUBE.COM/WATCH?
V=NLF0N9SACD4
Slide 65
Slide 65 text
function resourcefulOperation(value: number) {
let newValue
=
String(value);
for (let i
=
0; i < 1000000; i++) {
newValue
=
`${value} + ${i}
=
${value + i}`;
}
return newValue;
}
function ResourcefulComponent(props: { value: number }) {
const { value }
=
props;
const result
=
resourcefulOperation(value);
return
{result}
;
}
Slide 66
Slide 66 text
No content
Slide 67
Slide 67 text
🤓💻
EXPERIMENT #3
BUILDING A COROUTINES-BASED SCHEDULER
Slide 68
Slide 68 text
function resourcefulOperation(value: number) {
let newValue
=
String(value);
for (let i
=
0; i < 1000000; i++) {
newValue
=
`${value} + ${i}
=
${value + i}`;
}
return newValue;
}
function ResourcefulComponent(props: { value: number }) {
const { value }
=
props;
const result
=
resourcefulOperation(value);
return
{result}
;
}
Slide 69
Slide 69 text
function* resourcefulOperation(value: number) {
let newValue
=
String(value);
while (true) {
yield;
for (let i
=
0; i < 1000000; i++) {
newValue
=
`${value} + ${i}
=
${value + i}`;
}
return newValue;
}
}
const initialValue
=
0;
const scheduler
=
new Scheduler(resourcefulOperation, initialValue);
function ResourcefulComponent(props: { value: number }) {
const { value }
=
props;
const result
=
scheduler.performUnitOfWork(value);
return
{result}
;
}
Slide 70
Slide 70 text
function* resourcefulOperation(value: number) {
let newValue
=
String(value);
while (true) {
yield;
for (let i
=
0; i < 1000000; i++) {
newValue
=
`${value} + ${i}
=
${value + i}`;
}
return newValue;
}
}
const initialValue
=
0;
const scheduler
=
new Scheduler(resourcefulOperation, initialValue);
function ResourcefulComponent(props: { value: number }) {
const { value }
=
props;
const result
=
scheduler.performUnitOfWork(value);
return
{result}
;
}
/
/
PROMOTED TO A GENERATOR.
/
/
YIELDING INSIDE AN INFINITE LOOP.
/
/
DOING CONCURRENT STUFF.
function resourcefulOperation(value: number) {
let newValue
=
String(value);
for (let i
=
0; i < 1000000; i++) {
newValue
=
`${value} + ${i}
=
${value + i}`;
}
return newValue;
}
function ResourcefulComponent(props: { value: number }) {
const { value }
=
props;
const result
=
resourcefulOperation(value);
return
{result}
;
}
Slide 76
Slide 76 text
function resourcefulOperation(value: number) {
let newValue
=
String(value);
for (let i
=
0; i < 1000000; i++) {
newValue
=
`${value} + ${i}
=
${value + i}`;
}
return newValue;
}
function ResourcefulComponent(props: { value: number }) {
const [_, startTransition]
=
useTransition();
const [result, setResult]
=
useState("");
useEffect(()
=
>
{
startTransition(()
=
>
{
const newResult
=
resourcefulOperation(props.value);
setResult(newResult);
});
}, [props.value]);
return
{result}
;
}
Slide 77
Slide 77 text
No content
Slide 78
Slide 78 text
YES, WE DID 🤓
(USING SOME COROUTINES MAGIC)
Slide 79
Slide 79 text
↝ THERE’S NO USE OF WORKERS OR WASM FOR
PARALLELISM
↝ THERE’S A COOPERATIVE MULTITASKING MODEL
↝ A SINGLE RENDERING THREAD, BUT INTERRUPTIBLE
SO THAT RENDERING CAN BE INTERLEAVED WITH OTHER
MAIN THREAD TASKS AND OTHER REACT RENDERS
Slide 80
Slide 80 text
↓ ORIGINAL RENDER TASK
USER INPUT →
↑ HIGHER PRIORITY RENDER TASK
↓ RESUME ORIGINAL RENDER TASK
Slide 81
Slide 81 text
↝ AN UPDATE CAN HAPPEN IN THE BACKGROUND,
WITHOUT BLOCKING ANOTHER IN RESPONSE TO NEW
INPUT
↝ THE SCHEDULER SWITCHES TO THE MORE URGENT
RENDERING TASK, THEN PICKS THE ORIGINAL TASK UP
AFTER THAT HAS FINISHED
Slide 82
Slide 82 text
↝ IT YIELDS EXECUTION IS BACK TO THE MAIN THREAD
EVERY 5MS
↝ IT'S SMALLER THAN A SINGLE FRAME EVEN ON
120FPS DEVICES, SO IT WON'T BLOCK ANIMATIONS
↝ MOST INDIVIDUAL COMPONENTS DON'T TAKE LONGER
THAN A SINGLE FRAME TO RENDER
↝ IN PRACTICE, RENDERING IS EFFECTIVELY
INTERRUPTIBLE
Slide 83
Slide 83 text
Coroutines out
there
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 84
Slide 84 text
↝ ASYNCHRONY IN JAVASCRIPT IS CONTAGIOUS
↝ IF ANY FUNCTION IS ASYNC, THEN EVERYTHING THAT
CALLS IT MUST ALSO BE ASYNC…
↝ …AND SO ON UNTIL THE ENTIRE PROGRAM
IS ASYNCHRONOUS 🤷
Slide 85
Slide 85 text
↝ ASYNCHRONY IN JAVASCRIPT ISN’T FREE
↝ EVERY ASYNCHRONOUS FUNCTION CALL HAS TO:
↝ ALLOCATE CALLBACKS
↝ STORE THEM SOMEWHERE
↝ AND TAKE A TRIP BACK TO THE EVENT LOOP BEFORE
INVOKING THOSE CALLBACKS
Slide 86
Slide 86 text
No content
Slide 87
Slide 87 text
↝ ITS API HAS TWO MAIN FUNCTIONS FOR COMPILING
SASS FILES: ONE SYNC AND ONE ASYNC
↝ THE ASYNC ONE BECAME WIDELY USED IN PRACTICE
BECAUSE IT ENABLED ASYNC PLUGINS (E.G. WEBPACK’S
SASS-LOADER)
Slide 88
Slide 88 text
↝ FOR NODE SASS, THE PERFORMANCE DIFFERENCE WAS
NEGLIGIBLE, BECAUSE IT WAS BUILT ON C++
↝ HOWEVER, DART SASS RUNS AS PURE JAVASCRIPT,
WHICH MAKES IT SUBJECT TO JAVASCRIPT’S ASYNC
RULES
Slide 89
Slide 89 text
↝ THE ASYNC VERSION IN DART SASS WAS 2-3X SLOWER
THAN THE SYNC ONE
↝ THEY STARTED USING NODE-FIBERS TO IMPLEMENT THE
ASYNC API USING THE FAST, SYNC, CODE
Slide 90
Slide 90 text
HTTPS://GITHUB.COM/
LAVERDET/NODE-FIBERS
Slide 91
Slide 91 text
No content
Slide 92
Slide 92 text
Effect Handlers
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 93
Slide 93 text
↝ EFFECTS ASK THE CALLING ENVIRONMENT TO HANDLE A
PARTICULAR TASK
↝ WHEN AN EFFECT IS USED, THE NEAREST EFFECT
HANDLER IS CALLED, WHICH ALLOWS YOU TO RUN
CODE IN RESPONSE TO THE EFFECT AND RETURN
SOME VALUE.
🤯
A COMPONENT IS ABLE TO SUSPEND THE
FIBER IT IS RUNNING IN BY THROWING A
PROMISE, WHICH IS CAUGHT AND
HANDLED BY THE FRAMEWORK.
Slide 113
Slide 113 text
THROW → HANDLE → RESUME PATTERN.
A COMPONENT IS ABLE TO SUSPEND THE
FIBER IT IS RUNNING IN BY THROWING A
PROMISE, WHICH IS CAUGHT AND
HANDLED BY THE FRAMEWORK.
Slide 114
Slide 114 text
Conclusions
INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
Slide 115
Slide 115 text
1. REACT FIBER WAS A REWRITE OF
REACT FOCUSED ON GIVING MORE
LOW-LEVEL CONTROL OVER
PROGRAM EXECUTION
Slide 116
Slide 116 text
1.
↝ FIBERS AS A LOW-LEVEL
COOPERATIVE WAY TO MODEL
EXECUTION
↝ ALGEBRAIC EFFECTS AS A WAY
TO HANDLE EFFECTS WHERE
THESE AND THEIR BEHAVIOR
ARE INDEPENDENT
LOW-LEVEL CONTROL OVER
PROGRAM EXECUTION
Slide 117
Slide 117 text
2. REACT TRIES TO ADDRESS THE
LACK OF SOME JAVASCRIPT
FEATURES/LANGUAGE-LEVEL
RESOURCES BY IMPLEMENTING
SOME ALTERNATIVE SOLUTIONS TO
ACHIEVE SIMILAR BEHAVIORS
Slide 118
Slide 118 text
3. UNDERSTANDING THESE
INTERNALS AND THEIR
RATIONALES HELPS US IMPLEMENT
OUR OWN ABSTRACTIONS
Slide 119
Slide 119 text
HTTPS://WWW.YOUTUBE.COM/WATCH?
V=ADNJ3FYDEAO
Slide 120
Slide 120 text
4. REACT IS NOT REACTIVE, BUT IT
FEELS CONCURRENT
Slide 121
Slide 121 text
No content
Slide 122
Slide 122 text
5. THE FACT WE'RE DISCUSSING ALL
OF THESE TOPICS SHOWS THAT
REACT ACTS AS A DEMOCRATIC
AGENT FOR THIS KIND OF
KNOWLEDGE IN THE FRONT-END
WORLD
Slide 123
Slide 123 text
No content
Slide 124
Slide 124 text
THIS IS THE EIGHT-YEARS-AGO-ME GIVING A TALK ABOUT
IONIC AT AN IOS DEVELOPERS MEETUP TELLING THEM
THAT ANGULAR WOULD BE THE FUTURE.
Slide 125
Slide 125 text
6. DON’T ALWAYS TRUST ALL OF MY
SPECULATIONS/FUTURE
PREDICTIONS 🤷