Upgrade to Pro โ€” share decks privately, control downloads, hide ads and more โ€ฆ

๐Ÿ‡ณ๐Ÿ‡ฑ Frontmania 2022 - Inside Fiber

๐Ÿ‡ณ๐Ÿ‡ฑ Frontmania 2022 - Inside Fiber

Inside Fiber: the in-depth overview you wanted a TLDR for

We'll have an in-depth overview of the important concepts behind reconciliation and React Fiber. Then, we'll explore how React uses this algorithm and go through a few magic words we hear a lot, like coroutines, continuations, generators, and algebraic effectsโ€”and see how they all relate to React.

Avatar for Matheus Albuquerque

Matheus Albuquerque

October 04, 2022
Tweet

Video

More Decks by Matheus Albuquerque

Other Decks in Programming

Transcript

  1. Iโ€™M MATHEUS ๐Ÿ™‹ โ† @YTHECOMBINATOR ON THE WEB โ† SR.

    SOFTWARE ENGINEER @MEDALLIA โ† MENTOR @TECHLABS
  2. #1 REACT SOURCE CODE IS CONSTANTLY CHANGING, AND SOME THOUGHTS

    ARE SPECULATIONS INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
  3. #2 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR ๐Ÿคฏ = DEEP DIVE ๐Ÿคฟ, FURTHER DISCUSSIONS AFTER THE SESSION
  4. function add(x,y) { const result = x + y; return

    result; } add(2, 2) STACK FRAMES
  5. let frame: Frame = { return: frame, fn: add, parameters:

    [2, 2], localVariables: { result: 4, }, } STACK FRAMES
  6. let frame: Frame = { return: frame, fn: add, parameters:

    [2, 2], localVariables: { result: 4, }, } let fiber: Fiber = { return: fiber, component: Avatar, props: { id: 4 }, state: { isLoaded: true, }, } STACK FRAMES
  7. โ† 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 FIBERS
  8. 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. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  9. 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. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  10. 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. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  11. 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. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  12. 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. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE. A UNIT OF WORK.
  13. 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. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE. A UNIT OF WORK. AND THAT MAKES IT A CONVENIENT WAY TO TRACK, SCHEDULE, PAUSE AND ABORT THE WORK.
  14. 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; }
  15. 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; } ๐Ÿคฏ
  16. (let [x 1] (inc x)) ; = > 2 HOMOICONICITY

    PERFORMS A TEMPORARY BINDING (BINDS X TO THE VALUE 1)
  17. INCREMENTS X TO GIVE THE RETURN VALUE OF 2 (let

    [x 1] (inc x)) ; = > 2 HOMOICONICITY
  18. IT CAN BE THOUGHT OF AS A LIST WITH THREE

    ELEMENTS โ† A SYMBOL NAMED LET โ† A VECTOR WITH TWO ELEMENTS โ† A LIST WITH TWO ELEMENTS HOMOICONICITY
  19. IT CAN BE THOUGHT OF AS A LIST WITH THREE

    ELEMENTS โ† A SYMBOL NAMED LET โ† A VECTOR WITH TWO ELEMENTS โ† A LIST WITH TWO ELEMENTS HOMOICONICITY A SYMBOL (X) AND AN INTEGER A SYMBOL (INC) AND A SYMBOL (X)
  20. #QUOTE ๐Ÿค” โ€œโ€ฆ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.โ€ โ€”โ€‰Wikipedia
  21. โ† REACT ELEMENTS ARE JUST DATA โ† JUST LIKE IN

    LISP, REACT COMPONENTS CAN MANIPULATE THEIR CHILDREN AND RETURN COMPLETELY DIFFERENT THINGS HOMOICONICITY
  22. #QUOTE ๐Ÿค” โ€œ[โ€ฆ] Pattern matching consists of specifying patterns to

    which some data should conform and then checking to see if it does and deconstructing the data according to those patterns.โ€ โ€”โ€‰Learn You a Haskell
  23. factorial : : (Integral a) = > a - >

    a factorial 0 = 1 factorial n = n * factorial (n - 1) PATTERN MATCHING
  24. fib : : (Integral a) = > a - >

    a fib 0 = 1 fib 1 = 1 fib n | n > = 2 = fib (n-1) + fib (n-2) PATTERN MATCHING factorial =
  25. / / . . . export function isWhen<Shape extends {}>(

    child: ElementWithMetadataUnion<Shape> ): child is ElementWithMetadata<WhenProps<Shape > > { return child.element.type === When; } / / . . . export function nodesToElementWithMetadata<Shape extends {}>( children: ReactNode ) { return Children.toArray(children).map((element, idx) = > ({ element: element, position: idx, })) as Array<ElementWithMetadata<Shape > > ; } / / . . .
  26. / / . . . export function isWhen<Shape extends {}>(

    child: ElementWithMetadataUnion<Shape> ): child is ElementWithMetadata<WhenProps<Shape > > { return child.element.type === When; } / / . . . export function nodesToElementWithMetadata<Shape extends {}>( children: ReactNode ) { return Children.toArray(children).map((element, idx) = > ({ element: element, position: idx, })) as Array<ElementWithMetadata<Shape > > ; } / / . . .
  27. 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 ( <Suspense fallback="Loading"> <Match> <When predicate={supportsSensor}> <AmbientLight /> </When> <Otherwise> <Fallback /> </Otherwise> </Match> </Suspense> ); } PATTERN MATCHING
  28. 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 ( <Suspense fallback="Loading"> <Match> <When predicate={supportsSensor}> <AmbientLight /> </When> <Otherwise> <Fallback /> </Otherwise> </Match> </Suspense> ); } PATTERN MATCHING + REACT.SUSPENSE + REACT.LAZY() = USERS DOWNLOAD ONLY THE COMPONENT BUNDLE THAT MATCHES
  29. const supportsSensor + REACT.SUSPENSE + REACT.LAZY() = USERS DOWNLOAD ONLY

    THE COMPONENT BUNDLE THAT MATCHES MANIPULATING BASED ON ELEMENTS DATA.
  30. USING FIBERS, REACT CAN: โ† PAUSE, RESUME, AND RESTART RENDERING

    WORK ON COMPONENTS AS NEW UPDATES COME IN โ† REUSE PREVIOUSLY COMPLETED WORK โ† SPLIT WORK INTO CHUNKS AND PRIORITIZE TASKS BASED ON IMPORTANCE FIBERS IN REACT (RECAP)
  31. โ† A FIBER IS A GENERIC MODEL OF EXECUTION WHERE

    EACH UNIT WORKS TOGETHER COOPERATIVELY โ† FIBERS ARE A COMMON RESOURCE IN SOME OPERATING SYSTEMS (E.G. WINDOWS) AND IN SOME PROGRAMMING LANGUAGES (E.G. OCAML) FIBERS OUT THERE
  32. #1 A GENERATOR (PRODUCER) THAT CAN ALSO CONSUME VALUES. INSIDE

    FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
  33. #1 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR โ† JAVASCRIPT GENERATORS CAN CONSUME VALUES โ† BY THIS DEFINITION, THEY ARE COROUTINES A GENERATOR (PRODUCER) THAT CAN ALSO CONSUME VALUES.
  34. #2 A GENERATOR THAT CAN RESOLVE ASYNCHRONOUS VALUES, LIKE ASYNC/AWAIT.

    INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
  35. #2 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR โ† 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 VALUES, LIKE ASYNC/AWAIT.
  36. #3 A GENERATOR THAT CAN YIELD WITH A STACKFUL CONTINUATION

    INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
  37. #3 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR โ† "DEEP AWAIT" โ† e.g. WITH SUSPENSE, WE CAN PAUSE RECONCILIATION AT ANY DEPTH A GENERATOR THAT CAN YIELD WITH A STACKFUL CONTINUATION
  38. 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
  39. 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
  40. 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.
  41. COROUTINES & REACT โ† COROUTINES PER SI IN REACT NO

    LONGER EXIST. โ† IT WILL BE FASCINATING TO SEE WHAT FORM COROUTINES TAKE WHEN THEY RETURN TO REACT FIBER.
  42. 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 <p>{result}</p>; }
  43. 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 <p>{result}</p>; }
  44. 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 <p>{result}</p>; }
  45. 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 <p>{result}</p>; } PROMOTED TO A GENERATOR YIELDING EXECUTION DOING CONCURRENT TASKS
  46. enum SchedulerState { IDLE = "IDLE", PENDING = "PENDING", DONE

    = "DONE", } class Scheduler<T> { state: SchedulerState; result: T; worker: (data: T) = > Generator; iterator: Generator; constructor(worker: (data: T) = > Generator, initialResult: T) { this.state = SchedulerState.IDLE; this.worker = worker; this.result = initialResult; } performUnitOfWork(data: T) { switch (this.state) { case "IDLE": this.state = SchedulerState.PENDING; this.iterator = this.worker(data); throw Promise.resolve(); case "PENDING": const { value, done } = this.iterator.next(); if (done) { this.result = value; this.state = SchedulerState.DONE; return value; } throw Promise.resolve(); case "DONE": this.state = SchedulerState.IDLE; return this.result; } } }
  47. performUnitOfWork(data: T) { switch (this.state) { case "IDLE": this.state =

    SchedulerState.PENDING; this.iterator = this.worker(data); throw Promise.resolve(); case "PENDING": const { value, done } = this.iterator.next(); if (done) { this.result = value; this.state = SchedulerState.DONE; return value; } throw Promise.resolve(); case "DONE": this.state = SchedulerState.IDLE; return this.result; } }
  48. 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 <p>{result}</p>; }
  49. 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 <p>{result}</p>; }
  50. โ† A COOPERATIVE MULTITASKING MODEL โ† A SINGLE INTERRUPTIBLE RENDERING

    THREAD โ† RENDERING CAN BE INTERLEAVED WITH OTHER MAIN THREAD TASKS AND OTHER REACT RENDERS โ† AN UPDATE CAN HAPPEN IN THE BACKGROUND WITHOUT BLOCKING THE RESPONSE TO NEW INPUT COROUTINES & SCHEDULING
  51. โ†“ ORIGINAL RENDER TASK USER INPUT โ†’ โ†‘ HIGHER PRIORITY

    RENDER TASK โ†“ RESUME ORIGINAL RENDER TASK
  52. โ† IT YIELDS EXECUTION IS BACK TO THE MAIN THREAD

    EVERY 5MS โ† IT'S SMALLER THAN A SINGLE FRAME EVEN ON 120FPS, SO IT WON'T BLOCK ANIMATIONS โ† IN PRACTICE, RENDERING IS INTERRUPTIBLE COROUTINES & SCHEDULING
  53. COROUTINES & SCHEDULING const DailyVisitors = () = > {

    const [data, setData] = useState(initialData); useEffect(() = > { setData(initialData); }, []); const onChange = (newData) = > { setData(newData); }; return ( <Dashboard data={data} initialData={initialData} onChange={onChange} /> ); }; export default DailyVisitors;
  54. COROUTINES & SCHEDULING const DailyVisitors = () = > {

    const [data, setData] = useState(initialData); const [, startTransition] = useTransition(); useEffect(() = > { setData(initialData); }, []); const onChange = (newData) = > { startTransition(() = > { setData(newData); }); }; return ( <Dashboard data={data} initialData={initialData} onChange={onChange} /> ); }; export default DailyVisitors;
  55. โ† 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 ๐Ÿคท ASYNCHRONY & JS
  56. โ† ASYNCHRONY IN JAVASCRIPT ISNโ€™T FREE โ† EVERY ASYNCHRONOUS FUNCTION

    CALL HAS TO: โ† ALLOCATE CALLBACKS & STORE THEM SOMEWHERE โ† TAKE A TRIP BACK TO THE EVENT LOOP BEFORE INVOKING THOSE CALLBACKS ASYNCHRONY & JS
  57. โ† 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) ASYNCHRONY & SASS
  58. โ† 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 ASYNCHRONY & SASS
  59. โ† 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 ASYNCHRONY & SASS
  60. ๐Ÿคฏ APPROACH TO REASONING ABOUT COMPUTATIONAL EFFECTS IN PURE CONTEXTS

    โ† EFFECT โ‡ข A SET OF OPERATIONS โ† EFFECT HANDLER โ‡ข RESPONSIBLE FOR HANDLING THE SEMANTICS OF HOW TO IMPLEMENT EFFECTS EFFECT HANDLERS
  61. (* state.eff *) type user = string * int effect

    Get: user effect Set: user - > unit ๐Ÿคฏ EFFECT HANDLERS IN EFF
  62. (* state.eff *) type user = string * int effect

    Get: user effect Set: user - > unit A USER WITH A NAME AND AGE EFFECT HANDLERS IN EFF
  63. (* state.eff *) type user = string * int effect

    Get: user effect Set: user - > unit WE DEFINE EFFECTS WITH THE effect KEYWORD AND A TYPE SIGNATURE. EFFECT HANDLERS IN EFF
  64. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; ๐Ÿคฏ EFFECT HANDLERS IN EFF
  65. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; WE HAVE A handler WITH THREE BRANCHES, AND ALL OF THEM RETURN A FUNCTION. EFFECT HANDLERS IN EFF
  66. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; NO EFFECT (WHEN WE REACH THE END OF THE BLOCK). y IS THE RETURN VALUE. EFFECT HANDLERS IN EFF
  67. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; MATCHING OUR EFFECTS. EFFECT HANDLERS IN EFF
  68. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; k IS A CONTINUATION. IT REPRESENTS THE REST OF THE COMPUTATION AFTER WHERE WE PERFORM AN EFFECT. EFFECT HANDLERS IN EFF
  69. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } }
  70. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } }
  71. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } } THROW โ†’ PERFORM CATCH โ†’ HANDLE LETS US JUMP BACK TO WHERE WE PERFORMED THE EFFECT
  72. โ† IT DOESN'T REALLY MATTER HOW WE HOLD STATE. IF

    WE WERE TO CHANGE IN THE FUTURE, WEโ€™D NEED TO START HANDLING PROMISES, WHICH WOULD REQUIRE CHANGES ACROSS EVERYTHING. โ† WITH ALGEBRAIC EFFECTS, WE CAN SIMPLY STOP THE CURRENT PROCESS ALTOGETHER UNTIL OUR EFFECTS ARE FINISHED. EFFECT HANDLERS
  73. THE REACT TEAM APPARENTLY SPENT SOME TIME EXPERIMENTING WITH EFFECT-

    HANDLER CONTROL STRUCTURES FOR MANAGING LAYOUT
  74. #3 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR SIDE EFFECTS WITHIN A COMPONENT
  75. function ThemeBorderColorRequest() { } function FancyBox(children) { const color =

    raise new ThemeBorderColorRequest(); return { borderWidth: '1px', borderColor: color, children: children }; } function BlueTheme(children) { return try { children(); } catch effect ThemeBorderColorRequest - > [, continuation] { continuation('blue'); } } function App(data) { return BlueTheme( FancyUserList.bind(null, data.users) ); }
  76. function ThemeBorderColorRequest() { } function FancyBox(children) { const color =

    raise new ThemeBorderColorRequest(); return { borderWidth: '1px', borderColor: color, children: children }; } function BlueTheme(children) { return try { children(); } catch effect ThemeBorderColorRequest - > [, continuation] { continuation('blue'); } } function App(data) { return BlueTheme( FancyUserList.bind(null, data.users) ); } THROW โ†’ RAISE CATCH โ†’ CATCH EFFECT
  77. HOOKS API โ† ALGEBRAIC EFFECTS = A SET OF OPERATIONS

    AND A SET OF EFFECT HANDLERS โ† THE OPERATIONS HERE ARE OUR HOOKS (E.G. useState, useEffect, AND SO ON) โ† WE HAVE TO SET UP HANDLERS IN EFF; IN REACT THEY'RE SET UP AS PART OF THE RENDER CYCLE
  78. HOOKS API โ† REACT IS RESPONSIBLE FOR MUCH OF THE

    IMPLEMENTATION OF WHEN/HOW OUR EFFECTS RUN โ† IT ALLOWS US TO STASH ENORMOUS AMOUNTS OF COMPLEXITY WITHIN REACT โ† BY SPLITTING EFFECTS AND RENDERING, WE ALLOW IT TO RELIEVE US OF SOME COMPLEXITY
  79. A COMPONENT IS ABLE TO SUSPEND THE FIBER IT IS

    RUNNING IN BY THROWING A PROMISE, WHICH IS CAUGHT AND HANDLED BY THE FRAMEWORK.
  80. A COMPONENT IS ABLE TO SUSPEND THE FIBER IT IS

    RUNNING IN BY THROWING A PROMISE, WHICH IS CAUGHT AND HANDLED BY THE FRAMEWORK. THROW โ†’ HANDLE โ†’ RESUME PATTERN.
  81. #QUOTE ๐Ÿค” โ€œAt my heart, I am something like the

    goto instruction; my creation sets the label, and my methods do the jump. However, this is a really powerful kind of goto instruction. [โ€ฆ]โ€ โ€”โ€‰GNU Smalltalk Continuation documentation
  82. โ† ITโ€™S AN ABSTRACTION THAT REPRESENTS THE REMAINING STEPS IN

    A COMPUTATION, AFTER WHERE WE PERFORM AN EFFECT. โ† IT'S A CONTROL FLOW PRIMITIVE. โ† DIFFERENT FROM goto. ALL THE VARIABLES, POINTERS, ETC. ARE VALID. CONTINUATIONS
  83. function performWork(deadline) { while (tasks.length > 0) { const task

    = tasks.shift(); doTask(task); if ( tasks.length > 0 & & !deadline.didTimeout & & deadline.timeRemaining() < = 0 ) { return performWork; } } } scheduleWork(performWork); CONTINUATIONS IN REACT
  84. โ† IT HANDLES A QUEUE OF TASKS IN A WHILE

    LOOP โ† IF THERE ARE STILL TASKS ON THE QUEUE, IT RETURNS performWork AND SCHEDULE IT FOR RESUMPTION AT SOME LATER TIME โ† IN THIS CONTEXT, IT REPRESENTS THE CONTINUATION OF A QUEUE OF TASKS CONTINUATIONS IN REACT
  85. async function doWork() { while (true) { let hasMoreWork =

    doSomeWork(); if (!hasMoreWork) { return; } if (!navigator.scheduling.isInputPending()) { continue; } await scheduler.yield(); } } ๐Ÿคฏ CONTINUATIONS ON THE WEB
  86. #1 REACT FIBER WAS A REWRITE OF REACT FOCUSED ON

    GIVING MORE LOW-LEVEL CONTROL OVER PROGRAM EXECUTION INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
  87. #1 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR โ† 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 EXECUTION
  88. #2 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR REACT TRIES TO ADDRESS THE LACK OF SOME JAVASCRIPT FEATURES/ LANGUAGE-LEVEL RESOURCES BY IMPLEMENTING SOME ALTERNATIVE SOLUTIONS TO ACHIEVE SIMILAR BEHAVIORS E.G. EFFECT HANDLERS & CONTINUATIONS
  89. #3 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR UNDERSTANDING SOME OF THESE CONCEPTS GIVES US A BETTER MENTAL MODEL FOR WHAT SOME REACT FEATURES ARE DOING BEHIND THE SCENES E.G. HOOKS AND EFFECT HANDLERS
  90. #4 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR UNDERSTANDING THESE INTERNALS AND THEIR RATIONALES HELPS US IMPLEMENT OUR OWN ABSTRACTIONS E.G. THE COROUTINES-BASED SCHEDULER & THE PATTERN MATCHING COMPONENTS
  91. #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 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR FOR
  92. 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.
  93. #6 INSIDE FIBER: THE IN-DEPTH OVERVIEW YOU WANTED A TLDR

    FOR DONโ€™T ALWAYS TRUST ALL OF MY SPECULATIONS/FUTURE PREDICTIONS ๐Ÿคท