<p dir="auto">I just wanted to document a few unique design patterns that apply to Fiber, but not necessarily anything else. I'll start here.</p>
<ul dir="auto">
<li>You may mutate the fiber that you're working on during <code class="notranslate">beginWork</code> and <code class="notranslate">completeWork</code> phases but you may not have any other global side-effects. If you need a global side-effect, that have to be moved to the <code class="notranslate">commitWork</code> phase.</li>
<li>Fiber is a fixed data structure. It shares the same hidden class. Never add fields outside of construction in <code class="notranslate">ReactFiber</code>.</li>
<li>Nothing in the reconciler uses dynamic dispatch. I.e. we don't call a first class function, except for user code such as ref callbacks, functional components, render methods, etc. The rest is a static function available in a closure. I.e. use <code class="notranslate">myHelper(obj)</code> instead of <code class="notranslate">obj.myHelper()</code>. Any time we need to branch logic we use a switch statement over a <code class="notranslate">tag</code> which is a number that indicates which type of object we're dealing with and which branch to take (see pattern matching).</li>
<li>Many modules are instantiated with a <code class="notranslate">HostConfig</code> object. It is a single constructor that gets called on initialization time. This should be inlinable by a compiler.</li>
<li>Nothing in Fiber uses the normal JS stack. Meaning it does use the stack but it can be compiled into a flat function if needed. Calling other functions is fine - the only limitation is that they can't be recursive.</li>
<li>If I can't use recursion, how do I traverse through the tree? Learn to use the singly linked list tree traversal algorithm. E.g. parent first, depth first:</li>
</ul>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="let root = fiber;
let node = fiber;
while (true) {
  // Do something with node
  if (node.child) {
    node = node.child;
    continue;
  }
  if (node === root) {
    return;
  }
  while (!node.sibling) {
    if (!node.return || node.return === root) {
      return;
    }
    node = node.return;
  }
  node = node.sibling;
}"><pre class="notranslate"><span class="pl-k">let</span> <span class="pl-s1">root</span> <span class="pl-c1">=</span> <span class="pl-s1">fiber</span><span class="pl-kos">;</span>
<span class="pl-k">let</span> <span class="pl-s1">node</span> <span class="pl-c1">=</span> <span class="pl-s1">fiber</span><span class="pl-kos">;</span>
<span class="pl-k">while</span> <span class="pl-kos">(</span><span class="pl-c1">true</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-c">// Do something with node</span>
  <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">node</span><span class="pl-kos">.</span><span class="pl-c1">child</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-s1">node</span> <span class="pl-c1">=</span> <span class="pl-s1">node</span><span class="pl-kos">.</span><span class="pl-c1">child</span><span class="pl-kos">;</span>
    <span class="pl-k">continue</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">node</span> <span class="pl-c1">===</span> <span class="pl-s1">root</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  <span class="pl-k">while</span> <span class="pl-kos">(</span><span class="pl-c1">!</span><span class="pl-s1">node</span><span class="pl-kos">.</span><span class="pl-c1">sibling</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-c1">!</span><span class="pl-s1">node</span><span class="pl-kos">.</span><span class="pl-c1">return</span> <span class="pl-c1">||</span> <span class="pl-s1">node</span><span class="pl-kos">.</span><span class="pl-c1">return</span> <span class="pl-c1">===</span> <span class="pl-s1">root</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-k">return</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
    <span class="pl-s1">node</span> <span class="pl-c1">=</span> <span class="pl-s1">node</span><span class="pl-kos">.</span><span class="pl-c1">return</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  <span class="pl-s1">node</span> <span class="pl-c1">=</span> <span class="pl-s1">node</span><span class="pl-kos">.</span><span class="pl-c1">sibling</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Why does it need to be this complicated?</p>
<ul dir="auto">
<li>We can use the normal JS stack for this but any time we yield in a <code class="notranslate">requestIdleCallback</code> we would have to rebuild the stack when we continue. Since this only lasts for about 50ms when idle, we would spend some time unwinding and rebuilding the stack each time. It is not too bad. However, everything along the stack would have to be aware of how to "unwind" when we abort in the middle of the work flow.</li>
<li>It is plausible we could do this at the level of OCaml algebraic effects but we don't currently have all the features we need and we don't get the performance tradeoffs we want out of the box atm. This is a plausible future way forward though.</li>
<li>Most code lives outside of this recursion so it doesn't matter much for most cases.</li>
<li>Most of what React does is in the space of what the normal stack does. E.g. memoization, error handling, etc. Using the normal stack too, just makes it more difficult to get those to interact.</li>
<li>Everything we put on the stack we generally have to put on the heap too because we memoize it. Maintaining the stack and the heap with the same data is theoretically less efficient.</li>
<li>That said, all of these optimizations might be moot because JS stacks are much more efficient than JS heaps.</li>
<li>One thing that I wanted to try was to compile React components to do work directly on these data structures, just like normal programming languages compile to make mutations etc. to the stack. I think that's where the ideal implementation of React is.</li>
</ul>
<p dir="auto">Let's just try it and see how it goes. :D</p>
<p dir="auto">cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/spicyj/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/spicyj">@spicyj</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/gaearon/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/gaearon">@gaearon</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/acdlite/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/acdlite">@acdlite</a></p>
<p dir="auto">Describe what you were doing when the bug occurred:</p>
<ol dir="auto">
<li>I opened react profiler</li>
<li>I clicked "start profiling"</li>
<li>I performed some actions in my react application</li>
<li>I clicked "stop profiling"</li>
<li>Stacktrace appeared in devtools window instead of profiler charts.</li>
</ol>
<hr>
<h2 dir="auto">Please do not remove the text below this line</h2>
<p dir="auto">DevTools version: 4.8.1-d4eadea6c</p>
<p dir="auto">Call stack: at N (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:166989)<br>
at T (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:165979)<br>
at e.getCommitTree (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:168938)<br>
at Wl (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:346620)<br>
at oi (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:32:60964)<br>
at Ui (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:32:70944)<br>
at Bl (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:32:117704)<br>
at Tc (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:32:103070)<br>
at Oc (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:32:102998)<br>
at Dc (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:32:102861)</p>
<p dir="auto">Component stack: at Wl (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:346391)<br>
at div<br>
at div<br>
at div<br>
at Eo (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:266560)<br>
at chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:370969<br>
at n (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:279481)<br>
at chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:282269<br>
at div<br>
at div<br>
at Ji (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:329374)<br>
at Ge (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:209300)<br>
at sn (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:218616)<br>
at Wa (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:297360)<br>
at ps (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:40:376211)</p>