Анализ исходного кода реагирования волокна

React.js
Анализ исходного кода реагирования волокна

Изображение Артема Сапегина, источник:UN splash.com/photos/NO 18T…

Автор этой статьи: Лю Пэн

предисловие

В версии React v16.13 был официально запущен экспериментальный Concurrent Mode, особенно предоставляющий новый механизм Suspense, который естественным образом решил проблему асинхронных побочных эффектов, которая всегда существовала. В сочетании с хуками, представленными в версии 16.8, и Fiber, базовой архитектурой версии 16.0, React значительно улучшил возможности разработчиков и в определенной степени улучшил взаимодействие с пользователем. Итак, что вы можете ожидать от React 17?

Согласование стека и согласование волокон

Мы знаем, что примиритель стека - это алгоритм примирения, используемый React V15 и ранее. С другой стороны, реагируйте волокно, с другой стороны, переписывает примиритель стека из версии V16, который является основным алгоритмом реализации версии V16. Реализация откомителя стека использует синхронную модель рекурсии, которая опирается на встроенный стек для обхода. Эндрю из команды RACT упомянул это раньше:

Если вы только полагаетесь на встроенную стек вызовов, ему придется работать, пока стек не будет пуст, если мы свободны прерывать стек вызовов и вручную вручную кадр, что не хорошо? Волокно построен для повторной реализации стека, предназначенный для компонента React, волокно можно рассматривать как каркас виртуальной стеки.

Именно из-за внутренних ограничений встроенного средства согласования стека процесс обновления DOM является синхронным. То есть, если во время процесса сравнения виртуального DOM будет обнаружено, что экземпляр элемента обновлен, операция будет выполнена синхронно немедленно, и изменения будут отправлены в реальный DOM. Это может привести к очень плохому взаимодействию с пользователем в таких областях, как анимация, макет и жесты. Итак, чтобы решить эту проблему, React реализует фрейм виртуального стека. Фактически, этот так называемый кадр виртуального стека, по сути, создает несколько структур данных в виде связанных списков, содержащих узлы и указатели. Каждый узел является базовой единицей оптоволокна, и этот объект хранит определенную информацию о предметной области, связанную с компонентами. Указатель указывает на соединение всего дерева волокон. Очевидным преимуществом перенастройки стека является то, что вы можете хранить стеки в памяти и выполнять их при необходимости, что позволяет приостановить обход и остановить рекурсию стека.

Основная цель Fiber — включить инкрементный рендеринг виртуального DOM, возможность разделить работу рендеринга на куски и распределить их по нескольким кадрам. Возможность приостанавливать, прерывать и повторно использовать работу при поступлении нового обновления, а также возможность назначать порядок приоритета для различных типов обновлений. Понимание механизма работы React поможет нам лучше понять его конструктивные идеи и новые функции в последующих версиях, такие как возможности асинхронного рендеринга, которые могут появиться в версии 17. Я считаю, что это очень поможет. Эта статья основана на исходном коде React v16.8.6 и содержит некоторые простые идеи. Надеюсь, она поможет и вам. Если что-то не так, поправьте меня.

Основные понятия

Прежде чем разобраться в механизме реализации архитектуры React Fiber, необходимо откинуть несколько основных базовых понятий, чтобы мы могли лучше понять.

Work

В процессе React Reconciliation различные действия, которые должны выполнять вычисления, такие как обновление состояния, обновление реквизита или обновление ссылок и т. д., мы можем в совокупности назвать эти действия работой.

Волоконный объект

Расположение файла: Пакеты / Реактивно-примиреетель / SRC / ReviredFiber.js

Каждый элемент React соответствует объекту волокна, а объект волокна обычно является базовой единицей, представляющей работу. Объекты волокна имеют несколько свойств, которые указывают на другие объекты волокна.

  • дочерний: дочернее волокно, соответствующее родительскому узлу волокна
  • sibling: соответствует родственному узлу оптоволоконного узла.
  • возврат: родительский узел, соответствующий дочернему узлу волокна

Следовательно, волокна можно понимать как узел поля данных, содержащий контекстную информацию элементов React, и структуру связанного списка, состоящую из полей-указателей, таких как дочерний элемент, родственный элемент и возврат.

Основные свойства объекта волокна следующие:

Fiber = {
    // 标识 fiber 类型的标签,详情参看下述 WorkTag
    tag: WorkTag,

    // 指向父节点
    return: Fiber | null,

    // 指向子节点
    child: Fiber | null,

    // 指向兄弟节点
    sibling: Fiber | null,

    // 在开始执行时设置 props 值
    pendingProps: any,

    // 在结束时设置的 props 值
    memoizedProps: any,

    // 当前 state
    memoizedState: any,

    // Effect 类型,详情查看以下 effectTag
    effectTag: SideEffectTag,

    // effect 节点指针,指向下一个 effect
    nextEffect: Fiber | null,

    // effect list 是单向链表,第一个 effect
    firstEffect: Fiber | null,

    // effect list 是单向链表,最后一个 effect
    lastEffect: Fiber | null,

    // work 的过期时间,可用于标识一个 work 优先级顺序
    expirationTime: ExpirationTime,
};

Создайте объект волокна из элемента React

Расположение файла: react-reconciler/src/ReactFiber.js

export function createFiberFromElement(
    element: ReactElement,
    mode: TypeOfMode,
    expirationTime: ExpirationTime
): Fiber {
    const fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, expirationTime);
    return fiber;
}

workTag

Расположение файла: общий доступ/ReactWorkTags.js

Значение атрибута tag вышеуказанного объекта волокна, называемое workTag, используется для идентификации типа элемента React следующим образом:

export const FunctionComponent = 0;
export const ClassComponent = 1;
export const IndeterminateComponent = 2; // Before we know whether it is function or class
export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
export const HostComponent = 5;
export const HostText = 6;
export const Fragment = 7;
export const Mode = 8;
export const ContextConsumer = 9;
export const ContextProvider = 10;
export const ForwardRef = 11;
export const Profiler = 12;
export const SuspenseComponent = 13;
export const MemoComponent = 14;
export const SimpleMemoComponent = 15;
export const LazyComponent = 16;
export const IncompleteClassComponent = 17;
export const DehydratedSuspenseComponent = 18;
export const EventComponent = 19;
export const EventTarget = 20;
export const SuspenseListComponent = 21;

EffectTag

Расположение файла: общий/ReactSideEffectTags.js

Значение свойства effectTag вышеуказанного объекта волокна, каждый узел волокна имеет связанное с ним значение effectTag.
Мы называем некоторую работу, которую нельзя выполнить на этапе рендеринга, побочными эффектами.React перечисляет различные побочные эффекты, которые могут существовать, следующим образом:

export const NoEffect = /*              */ 0b000000000000;
export const PerformedWork = /*         */ 0b000000000001;

export const Placement = /*             */ 0b000000000010;
export const Update = /*                */ 0b000000000100;
export const PlacementAndUpdate = /*    */ 0b000000000110;
export const Deletion = /*              */ 0b000000001000;
export const ContentReset = /*          */ 0b000000010000;
export const Callback = /*              */ 0b000000100000;
export const DidCapture = /*            */ 0b000001000000;
export const Ref = /*                   */ 0b000010000000;
export const Snapshot = /*              */ 0b000100000000;
export const Passive = /*               */ 0b001000000000;

export const LifecycleEffectMask = /*   */ 0b001110100100;
export const HostEffectMask = /*        */ 0b001111111111;

export const Incomplete = /*            */ 0b010000000000;
export const ShouldCapture = /*         */ 0b100000000000;

Примирение и планирование

Примирение:
Короче говоря, виртуальный DOM сравнивается по алгоритму diff, который позволяет определить, какие части элементов React нужно изменить.

Планирование:
Его можно просто понимать как процесс определения времени выполнения работы.

Стадия рендеринга и стадия фиксации

Думаю, многие студенты видели эту картинку — диаграмму этапов жизненного цикла, нарисованную автором команды React Дэном Абрамовым.Нажмите, чтобы просмотреть подробности.他把 React 的生命周期主要分为两个阶段:render 阶段和 commit 阶段。其中 commit 阶段又可以细分为 pre-commit 阶段和 commit 阶段,如下图所示:

image.png

Начиная с версии V16.3, на этапе рендеринга следующие жизненные циклы считаются небезопасными, они будут удалены в будущих версиях, вы можете видеть, что эти жизненные циклы не включены в приведенную выше картинку, как показано ниже.

  • [UNSAFE_]componentWillMount (deprecated)
  • [UNSAFE_]componentWillReceiveProps (deprecated)
  • [UNSAFE_]componentWillUpdate (deprecated)

Причины отказа четко указаны на официальном сайте React.Эти жизненные циклы, помеченные как небезопасные, часто неправильно понимаются или даже злоупотребляются разработчиками.Например, некоторые разработчики склонны размещать в них логику с побочными эффектами, такими как запрос данных.В жизненном цикле метод, считается, что он может принести лучшую производительность, но на самом деле реальные выгоды почти ничтожны. В будущем React будет постепенно продвигать режим асинхронного рендеринга, который, вероятно, вызовет много проблем из-за несовместимости.

На этапе рендеринга React может обрабатывать один или несколько узлов волокна в соответствии с доступным в данный момент интервалом времени, а благодаря информации о контексте элемента, хранящейся в объекте волокна, и структуре связанного списка, сформированной полем указателя, он может сэкономить половину работа, выполняемая в связанном списке в памяти. После того, как React остановится и выполнит сохраненную работу, освободите временной отрезок для других вещей с более высоким приоритетом. После этого, после повторного захвата доступного временного интервала, он может найти остановленный волоконный узел быстрым обходом и продолжить работу в соответствии с ранее сохраненной в памяти контекстной информацией. Поскольку работа, выполняемая на этом этапе, не приводит к видимым для пользователя изменениям, она не фиксируется в реальном DOM. Итак, мы говорим о волокнах, которые дают планировщикам возможность приостанавливать, прерывать и перезапускать инкрементный рендеринг. Напротив, на этапе фиксации выполнение работы всегда синхронно, поскольку работа, выполняемая на этом этапе, приводит к видимым для пользователя изменениям. Вот почему на этапе фиксации React должен зафиксировать и выполнить всю работу одновременно.

Текущее дерево и дерево WorkInProgress

После первого рендеринга React генерирует дерево волокон, соответствующее рендерингу пользовательского интерфейса, называемое текущим деревом. На самом деле, React различает, когда выполнять componentDidMount и componentDidUpdate, оценивая наличие тока при вызове функции ловушки жизненного цикла. Когда React проходит по текущему дереву, он создает заменяющий узел для каждого существующего узла волокна, которые образуют дерево workInProgress. Вся последующая работа происходит в дереве workInProgress.Если дерево не было создано, будет создана копия текущего дерева как дерево workInProgress. Когда дерево workInProgress зафиксировано, оно будет заменено текущим деревом на подфазе фазы фиксации.

Основная причина добавления двух деревьев здесь — избежать потери обновлений. Например, если мы добавляем обновления только в дерево workInProgress, некоторые обновления могут быть потеряны при перезапуске дерева workInProgress путем клонирования из текущего дерева. Аналогичным образом, если мы добавим обновления только к текущему дереву, при фиксации дерева workInProgress оно будет заменено текущим деревом, а обновления будут потеряны. Сохранение обновлений в обеих очередях гарантирует, что обновления всегда будут частью следующего дерева workInProgress. Кроме того, поскольку дерево workInProgress зафиксировано как текущее дерево, нет возможности применить одно и то же обновление дважды.

Effects list

Список эффектов можно понимать как контейнер для хранения списка побочных эффектов effectTag. Это односвязная структура списка, состоящая из узлов волокна и указателя nextEffect, который также включает первый узел firstEffect и последний узел lastEffect. Как показано ниже:

image.png

React использует алгоритм поиска в глубину.При обходе дерева волокон на этапе рендеринга он отфильтровывает каждое волокно с побочными эффектами и, наконец, строит и генерирует связанный список списков эффектов только с побочными эффектами.
На этапе фиксации, после того как React получает данные списка эффектов, он проходит по списку эффектов и изменяет соответствующее дерево DOM в соответствии с типом effectTag каждого узла эффекта.

Для демонстрации процесса построения списка эффектов вы можете щелкнуть, чтобы просмотреть анимацию.«Список эффектов - еще один процесс построения связанного списка волокон».

Этап рендеринга

В этой статье мы возьмем компонент класса в качестве примера, предполагая, что метод setState уже был вызван.

enqueueSetState

У каждого компонента React есть связанный модуль обновления, который действует как мост между слоем компонента и основной библиотекой.
react.Component - это, по сути, функция с методом setState, смонтированным на объекте-прототипе.

Расположение файла: реакция/src/ReactBaseClasses.js

// Component函数
function Component(props, context, updater) {
    this.props = props;
    this.context = context;
    this.updater = updater || ReactNoopUpdateQueue;
}

// Component原型对象挂载 setState
Component.prototype.setState = function (partialState, callback) {
    this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

React грубо делит работу на следующие типы приоритетов. Среди них немедленная является особой. Она имеет наивысший приоритет. Ее можно понимать как синхронное планирование, и процесс планирования не будет прерываться.

export const NoPriority = 0;
export const ImmediatePriority = 1;
export const UserBlockingPriority = 2;
export const NormalPriority = 3;
export const LowPriority = 4;
export const IdlePriority = 5;

В React есть набор логики вычислений, которая вычисляет время истечения expireTime для разных работ в соответствии с разными типами приоритетов, что на самом деле является меткой времени. Так называемая способность React назначать порядок приоритета для различных типов обновлений при поступлении нового обновления по существу основана на размере времени истечения expireTime для определения порядка приоритета.Чем меньше значение expireTime, тем выше приоритет. Работы, которые находятся в пределах определенного временного диапазона, React будет считать их находящимися в одном пакете, поэтому этот пакет работ будет выполнен за одно обновление.

Расположение файла: react-reconciler/src/ReactFiberClassComponent.js

const classComponentUpdater = {
    enqueueSetState(inst, payload, callback) {
        // 获取 fiber 对象
        const fiber = getInstance(inst);
        const currentTime = requestCurrentTime();

        // 计算到期时间 expirationTime
        const expirationTime = computeExpirationForFiber(currentTime, fiber, suspenseConfig);

        const update = createUpdate(expirationTime, suspenseConfig);
        // 插入 update 到队列
        enqueueUpdate(fiber, update);
        // 调度 work 方法
        scheduleWork(fiber, expirationTime);
    },
};

renderRoot

Расположение файла: react-reconciler/src/ReactFiberWorkLoop.js

Процесс согласования всегда начинается с renderRoot, а стек вызовов методов: scheduleWork --> scheduleCallbackForRoot --> renderRoot

код показывает, как показано ниже:

function renderRoot(
  root: FiberRoot,
  expirationTime: ExpirationTime,
  isSync: boolean,
) | null {
  do {
    // 优先级最高,走同步分支
    if (isSync) {
      workLoopSync();
    } else {
      workLoop();
    }
  } while (true);
}

// 所有的fiber节点都在workLoop 中被处理
function workLoop() {
  while (workInProgress !== null && !shouldYield()) {
    workInProgress = performUnitOfWork(workInProgress);
  }
}

performUnitOfWork

Все узлы волокна обрабатываются в методе workLoop. Процесс координации всегда проходит по дереву workInProgress, начиная с самого верхнего узла hostRoot. Однако React будет пропускать уже обработанные узлы волокна, пока не найдет узел, который еще не выполнил работу. Например, если вы вызываете setState глубоко в дереве компонентов, React начнет с самого верха, но быстро пропустит родительские узлы, пока не достигнете компонента, вызвавшего метод setState. Весь процесс использует алгоритм поиска в глубину.После обработки текущего узла волокна workInProgress будет содержать ссылку на следующий узел волокна в дереве.Если следующий узел имеет значение null и не существует, считается, что выполнение завершается и выходит из цикла workLoop и снова готов к работе.

Стек вызовов методов выглядит следующим образом: PerformUnitOfWork --> beginWork --> updateClassComponent --> FinishedComponent --> CompleteUnitOfWork

Код выглядит следующим образом:

Расположение файла: react-reconciler/src/ReactFiberWorkLoop.js

function performUnitOfWork(unitOfWork: Fiber): Fiber | null {
    const current = unitOfWork.alternate;

    let next;
    next = beginWork(current, unitOfWork, renderExpirationTime);

    // 如果没有新的 work,则认为已完成当前工作
    if (next === null) {
        next = completeUnitOfWork(unitOfWork);
    }

    return next;
}

Чтобы понять алгоритм поиска в глубину дерева, вы можете щелкнуть, чтобы обратиться к примеру"js-ntqfill".

completeUnitOfWork

Расположение файла: react-reconciler/src/completeUnitOfWork.js

Создайте связанный список эффектов в методе completeUnitOfWork. Список эффектов очень важен на следующем этапе фиксации. Список эффектов описан выше.

Следующим образом:

function completeUnitOfWork(unitOfWork: Fiber): Fiber | null {
    // 深度优先搜索算法
    workInProgress = unitOfWork;
    do {
        const current = workInProgress.alternate;
        const returnFiber = workInProgress.return;

        /*
    	构建 effect-list部分
    */
        if (returnFiber.firstEffect === null) {
            returnFiber.firstEffect = workInProgress.firstEffect;
        }
        if (workInProgress.lastEffect !== null) {
            if (returnFiber.lastEffect !== null) {
                returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;
            }
            returnFiber.lastEffect = workInProgress.lastEffect;
        }

        if (returnFiber.lastEffect !== null) {
            returnFiber.lastEffect.nextEffect = workInProgress;
        } else {
            returnFiber.firstEffect = workInProgress;
        }
        returnFiber.lastEffect = workInProgress;

        const siblingFiber = workInProgress.sibling;
        if (siblingFiber !== null) {
            // If there is more work to do in this returnFiber, do that next.
            return siblingFiber;
        }
        // Otherwise, return to the parent
        workInProgress = returnFiber;
    } while (workInProgress !== null);
}

На этом этап рендеринга, вероятно, закончен.

Стадия фиксации

На этапе фиксации React обновляет реальный DOM и вызывает методы жизненного цикла фазы предварительной фиксации и фазы фиксации. В отличие от фазы рендеринга, выполнение фазы фиксации всегда синхронно и для завершения будет полагаться на список эффектов, созданный на предыдущей фазе рендеринга.

commitRootImpl

Этап фиксации по существу делится на следующие три подэтапа:

  • before mutation
  • mutation phase
  • layout phase

Главное на этапе мутации — пройтись по списку эффектов, получить информацию, хранимую каждым эффектом, выполнить соответствующую обработку в соответствии с типом побочного эффекта effectTag и отправить обновление в реальный DOM. Все эффекты мутации обрабатываются перед фазой компоновки. Когда выполнение этой фазы завершается, дерево workInProgress заменяется текущим деревом. Таким образом, на подфазе перед мутацией, перед фазой мутации вызывается жизненный цикл getSnapshotBeforeUpdate. На этапе до мутации реальный DOM не изменился. Последняя подфаза — это фаза компоновки, на которой выполняется компонент жизненного циклаDidMount/Update.

Расположение файла: react-reconciler/src/ReactFiberWorkLoop.js

Следующим образом:

function commitRootImpl(root) {
    if (firstEffect !== null) {
        // before mutation 阶段,遍历 effect list
        do {
            try {
                commitBeforeMutationEffects();
            } catch (error) {
                nextEffect = nextEffect.nextEffect;
            }
        } while (nextEffect !== null);

        // the mutation phase 阶段,遍历 effect list
        nextEffect = firstEffect;
        do {
            try {
                commitMutationEffects();
            } catch (error) {
                nextEffect = nextEffect.nextEffect;
            }
        } while (nextEffect !== null);

        // 将 work-in-progress 树替换为 current 树
        root.current = finishedWork;

        // layout phase 阶段,遍历 effect list
        nextEffect = firstEffect;
        do {
            try {
                commitLayoutEffects(root, expirationTime);
            } catch (error) {
                captureCommitPhaseError(nextEffect, error);
                nextEffect = nextEffect.nextEffect;
            }
        } while (nextEffect !== null);

        nextEffect = null;
    } else {
        // No effects.
        root.current = finishedWork;
    }
}

commitBeforeMutationEffects

ссылка перед вызовом мутации: commitRootImpl --> commitBeforeMutationEffects --> commitBeforeMutationLifeCycles

код показывает, как показано ниже:

function commitBeforeMutationLifeCycles(
  current: Fiber | null,
  finishedWork: Fiber,
): void {
  switch (finishedWork.tag) {
    case FunctionComponent:
    case ForwardRef:
    case SimpleMemoComponent:
    ...
    // 属性 stateNode 表示对应组件的实例
    // 在这里 class 组件实例执行 instance.getSnapshotBeforeUpdate()
    case ClassComponent: {
      if (finishedWork.effectTag & Snapshot) {
        if (current !== null) {
          const prevProps = current.memoizedProps;
          const prevState = current.memoizedState;
          const instance = finishedWork.stateNode;
          const snapshot = instance.getSnapshotBeforeUpdate(
            finishedWork.elementType === finishedWork.type
              ? prevProps
              : resolveDefaultProps(finishedWork.type, prevProps),
            prevState,
          );

          instance.__reactInternalSnapshotBeforeUpdate = snapshot;
        }
      }
      return;
    }
    case HostRoot:
    case HostComponent:
    case HostText:
    case HostPortal:
    case IncompleteClassComponent:
      ...
  }
}

commitMutationEffects

Расположение файла: react-reconciler/src/ReactFiberWorkLoop.js

Фаза фазы мутации вызывает цепочку: commitRootImpl --> commitMutationEffects --> commitWork

код показывает, как показано ниже:

function commitMutationEffects() {
  while (nextEffect !== null) {
    const effectTag = nextEffect.effectTag;

    let primaryEffectTag = effectTag & (Placement | Update | Deletion);
    switch (primaryEffectTag) {
      case Placement:
        ...
      case PlacementAndUpdate:
        ...
      case Update: {
        const current = nextEffect.alternate;
        commitWork(current, nextEffect);
        break;
      }
      case Deletion: {
        commitDeletion(nextEffect);
        break;
      }
    }
  }
}

commitLayoutEffects

Расположение файла: react-reconciler/src/ReactFiberCommitWork.js

Ссылка на вызов фазы макета: commitRootImpl --> commitLayoutEffects --> commitLifeCycles

код показывает, как показано ниже:

function commitLifeCycles(
  finishedRoot: FiberRoot,
  current: Fiber | null,
  finishedWork: Fiber,
  committedExpirationTime: ExpirationTime,
): void {
  switch (finishedWork.tag) {
    case FunctionComponent:
    case ForwardRef:
    case SimpleMemoComponent:
      ...
    case ClassComponent: {
      // 属性 stateNode 表示对应组件的实例
      // 在这里 class 组件实例执行 componentDidMount/DidUpdate
      const instance = finishedWork.stateNode;
      if (finishedWork.effectTag & Update) {
        // 首次渲染时,还没有 current 树
        if (current === null) {
          instance.componentDidMount();
        } else {
          const prevProps =
            finishedWork.elementType === finishedWork.type
              ? current.memoizedProps
              : resolveDefaultProps(finishedWork.type, current.memoizedProps);
          const prevState = current.memoizedState;
          instance.componentDidUpdate(
            prevProps,
            prevState,
            instance.__reactInternalSnapshotBeforeUpdate,
          );
        }
      }
      const updateQueue = finishedWork.updateQueue;
      if (updateQueue !== null) {
        commitUpdateQueue(
          finishedWork,
          updateQueue,
          instance,
          committedExpirationTime,
        );
      }
      return;
    }
    case HostRoot:
    case HostComponent:
    case HostText:
    case HostPortal:
    case Profiler:
    case SuspenseComponent:
    case SuspenseListComponent:
      ...
  }
}

расширять

Вот несколько расширений для Fiber.

ссылка для вызова

Как показано на рисунке ниже, диаграмма связи вызовов, нарисованная в соответствии с исходным кодом React, в основном перечисляет некоторые из наиболее важных методов функций, которые можно использовать в качестве справочного материала для всех, кто хочет понять Fiber. В процессе отладки исходного кода вы можете найти соответствующие точки останова метода функции, чтобы понять фактический выполняемый процесс, чтобы лучше разобраться в отношениях между различными логическими методами.

fiber调用链路.jpg

requestIdleCallback

Подводя итог принципу планирования React Fiber, в предыдущей статье упоминалось, что клиентский поток будет разделен на кадры при выполнении задач. Между двумя кадрами выполнения основной поток обычно имеет короткий период простоя, и во время этого простоя срабатывает requestIdleCallback. период.метод, который может выполнять некоторую работу с более низким приоритетом.

Говорят, что это действительно делалось в ранних версиях React, но на самом деле есть некоторые ограничения в использовании requestIdleCallback, да и частота выполнения недостаточна, так что плавного рендеринга UI добиться не получается, а масштабируемость плохая. Поэтому команда React отказалась от использования requestIdleCallback и реализовала пользовательскую версию. Например, в релизе v16.10 был представлен экспериментальный Scheduler, который пытался использовать postMessage вместо requestAnimationFrame. Для получения дополнительной информации ознакомьтесь с разделом packages/scheduler исходного кода React.

резюме

Fiber имеет долгую историю, и можно сказать, что он является типичным воплощением дизайнерских идей React. По сравнению с другими популярными в отрасли библиотеками, при поступлении новых данных больше используется режим пересчета React придерживается режима pull, то есть может откладывать использование вычислительных ресурсов до тех пор, пока это не потребуется, и знает, когда ему больше подходит выполнять и когда не выполнять. Может показаться, что это небольшая разница, но она имеет большой смысл. С последующим введением новых функций, таких как возможности асинхронного рендеринга, у нас есть основания полагать, что в будущем React преподнесет нам больше сюрпризов в применении взаимодействия человека с компьютером.

Ссылаться на

Эта статья была опубликована сКоманда внешнего интерфейса NetEase Cloud Music, Любое несанкционированное воспроизведение статьи запрещено. Мы набираем front-end, iOS и Android круглый год.Если вы готовы сменить работу и любите облачную музыку, присоединяйтесь к нам на grp.music-fe(at)corp.netease.com!