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

  • 828