Анализ принципа React Fiber

React.js

предисловие

Сегодня, катаясь на своем любимом электрическом ослике, я шла по улице в раздумьях, и вдруг передо мной появился мальчик на вынос Ele.me, а в правом нижнем углу коробки на вынос было внушительно написано .Carbon Fiber(碳纤维),оказалосьFiberЕго тоже можно использовать! ! ! Такое чувство, что я открыл свои две вены Рена и Ду, и я в одно мгновение оказался прав.FiberПонимание этого слова улучшилось как на дрожжах! Используется инкубатор.Carbon Fiber, Кажется, что это действительно большое усилие!

ReactКоманда переписалаReactОсновной алгоритм ---reconciliation, предыдущий алгоритм обычно называетсяstack reconciliation, теперь называетсяfiber reconciliation.

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

1. Проблемы с React V15.x

В сценариях с большим количеством элементов страницы, которые необходимо часто обновлять,React V15.xПроисходит падение кадров. Вот очень классический пример:

Ссылка на ссылку:Клаудио pro.GitHub.IO/react-fiber…

На изображении выше вы можете увидеть очевидный феномен пропуска кадров. Причина в том, что большое количество синхронных вычислительных задач блокирует работу браузера.UIоказывать. Потому что по умолчаниюJSОперации, макет страницы и отрисовка страницы выполняются в основном потоке браузера и являются взаимоисключающими. еслиJSОперация продолжает занимать основной поток, и страница не может быть обновлена ​​вовремя. когда мы звонимsetStateПри обновлении страницы,ReactОн пройдет по всем узлам приложения, рассчитает разницу, а затем обновитUI. Весь процесс нельзя прерывать. Если на странице много элементов, весь процесс может занять более16ms, легко пропустить кадры.

существуетDom-DiffТо же самое верно и для рекурсивного сравнения обхода, и есть две проблемы, которые очень сильно влияют на производительность:

  • Когда узел дерева огромен, это приводит к тому, что стек выполнения рекурсивных вызовов становится все глубже и глубже.
  • Выполнение нельзя прервать, страница будет ждать завершения рекурсивного выполнения перед повторным рендерингом.

Для решения этой проблемы,ReactКоманда сталкивается с уровня каркасаwebРабочий механизм страницы был оптимизирован, и это дало хорошие результаты. Схема эффекта выглядит следующим образом:

Во-вторых, как решить

Решите проблему, что основной поток заблокирован в течение длительного времени JSОсновная идея задачи о занятии операции состоит в том, чтобы разделить операцию на несколько шагов и выполнять их партиями. То есть после выполнения некоторых задач управление возвращается браузеру, чтобы у браузера было время отобразить страницу. Подождите, пока браузер не будет занят, прежде чем продолжить ранее незавершенную задачу.

ReactРазделяйте задачи на маленькие части и выполняйте их в короткие промежутки времени.分片任务, позвольте основному потоку делать дела с более высоким приоритетом, и если есть что-то ожидающее, вернуться, чтобы закончить работу. ОдинFiberэто единица работы,ReactОсновная концепцияUI является проекцией данных, суть компонента можно рассматривать как входные данные, выходныеUIописание информации (虚拟DOM树),который:

ui = f(data)

То есть рендерингReact app, на самом деле вызывает функцию. Функция сама будет вызывать другие функции для формирования стека вызовов. Стек вызовов, вызванный рекурсивным вызовом, находится вне нашего контроля и может быть выполнен только один раз. а такжеFiberПросто чтобы решить эту проблему, вы можете прерывать стек вызовов по мере необходимости и вручную управлятьstack frame- В этой связи,Fiber можно понимать как virtual stack frame.

старая версияReactРекурсивный рендеринг с использованиемJSСтек вызовов функций самого движка, он будет выполняться до тех пор, пока стек не опустеет. а такжеFiberРеализован собственный стек вызовов компонентов, который обходит дерево компонентов в виде связанного списка и может гибко приостанавливать, возобновлять и отбрасывать выполненные задачи. Способ сделать это использовать браузерrequestIdleCallbackэтоAPI. Официальное объяснение таково:

window.requestIdleCallback()会在浏览器空闲时期依次调用函数,这就可以让开发者在主事件循环中执行后台和低优先级的任务,而且不会对像动画和输入响应等用户交互这些延迟触发但关键的事件产生影响。函数一般会按先进先调用的顺序执行,除非函数在浏览器调用它之前就到了它的超时时间。

Справочная документация:developer.Mozilla.org/this-cn/docs/…

Разделение волокна

Поскольку задача должна быть разделена на небольшие задачи, должен быть разделенный план.

FiberСхема разделения основана на виртуальномDOMразделить, потому чтоfiber treeосновывается наVirtual DOM tree Структура та же, но информация, которую несут узлы, отличается.

Таким образом, каждый экземпляр компонента и каждыйDOMАбстрактное представление узла — это единица работы, которая обрабатывается по одной в рабочем цикле.fiber, После обработки одного он определит, есть ли задачи с высоким приоритетом или достаточно ли оставшегося времени, и может продолжить обработку, приостановить или завершить рабочий цикл.

Рабочий цикл согласования оптоволокна

  1. Найдите корневой узел с наивысшим приоритетомworkInProgress tree, в зависимости от обрабатываемого узла (представляющего компонент или узел DOM)
  2. Проверяем, нужно ли обновлять текущий узел, если нет, переходим сразу к 4
  3. отметить этоtag), обновить себя (обновление компонентаprops,contextЖдать,DOMпримечание к узлуDOM change),провестиreconcileChildrenи вернутьсяworkInProgress.child
  4. не существуетworkInProgress.child, оказывается листовым узлом, собираем вверхeffect
  5. Пучокchildилиsiblingтак какnextUnitWork, введите следующий рабочий цикл. если обратноworkInProgress treeкорневой узел, рабочий цикл заканчивается
  6. Войтиcommitсцена

Рабочая фаза волокна

  1. diff renderа такжеreconciliationв основном строятworkInProgress tree,ФактическиdiffОбработать
  2. complete diffProperties,отметкаtag,собиратьeffect
  3. commitСтадия фиксации, применение обновлений

Технология workInProgress с двойным буферным пулом

Fiber调度算法Взятый双缓冲池算法,FiberRootВсе узлы ниже попытаются создать свои собственные «зеркала» в процессе работы алгоритма.

workInProgress treeдаreconcileпроцесс изfiber treeСнимок текущего прогресса создан, вся работа выполняется в этом дереве, используется для расчета обновлений, завершенияreconciliationОбработать.

workInProgress.alternate = current;
current.alternate = workInProgress;

он и токfiberпройти черезalternateсоздавать ассоциации, строитьworkInProgress, возьметcurrent.alternate, повторно используйте, если он существует, и создайте, если он не существует. Это позволяет повторно использовать внутренние объекты (fiber), экономя выделение памяти,GCстоимость времени.

workInProgress treeПосле завершения строительства получается новыйfiber tree, при входеcommitсценаcurrentуказал наworkInProgress.

root.current = finishedWork;

Основная идея — технология двойного буферного пула (double buffering pooling technique), потому что необходимо сделатьdiffЕсли да, то следует сравнить как минимум два дерева. Таким образом, общее количество деревьев может быть ограничено до2, узлы и атрибуты узлов создаются лениво, чтобы свести к минимуму рост использования памяти из-за процесса алгоритма.

Двойная буферизация двух деревьевFiberNode Treeобмен ролями, оригиналworkInProgressПравильный.

Стратегия обновления с двойной буферизацией

  • После каждого рендерингаfiberприсвоение дереваcurrentRoot
  • Первое обновление будетrooterFiberизalternateУкажите на последний визуализированныйcurrentRoot
  • Обновления после второго будутworkInProgressRootнаправлениеcurrentRoot.alternate, то токworkInProgressRoot.alternateУкажите на последний визуализированныйcurrentRoot
  • ...
  • добиться повторного использованияfiberдерево объектов

После того, как у нас есть представление о проблеме, давайте посмотримReactкак именно.

3. Решения

React Внутреннюю работу фреймворка можно разделить на 3 уровня:

  • Virtual DOMСлой, который описывает, как выглядит страница.
  • Reconcilerуровень, отвечающий за вызов методов жизненного цикла компонента, выполнениеDiffоперации и др.
  • RendererСлой, в зависимости от разных платформ, отображает соответствующую страницу, чем чащеReactDOM а такжеReactNative.

следовательноVirtual DOM,Dom diff,Fiber,RendererИ т.д. это не отдельное понятие! Скорее, они взаимосвязаны и дополняют друг друга!

Среди них больше всего изменился слой Reconciler, и команда React также дала ему новое имя:Fiber Reconciler. то естьFiber.

FiberНа самом деле это относится к структуре данных, которую можно использовать с чистымJS объект для представления:

const fiber = {
    stateNode,    // 节点实例
    child,        // 子节点
    sibling,      // 兄弟节点
    return,       // 父节点
}

Чтобы отличить предыдущийReconcilerНазван какStack Reconciler.Stack ReconcilerПроцесс операции нельзя прерывать, и он должен идти до темноты:

а такжеFiber ReconcilerКаждый раз, когда он выполняется в течение определенного периода времени, управление возвращается браузеру, который может выполняться по секциям:

Для того, чтобы добиться такого эффекта, необходимо иметь планировщик (Scheduler) ставить задачи. Существует шесть приоритетов задач:

  • synchronous, с предыдущимStack ReconcilerТа же операция, синхронное выполнение
  • task,существуетnext tickвыполнить до
  • animation, выполняется перед следующим кадром
  • high, который будет выполнен немедленно в ближайшее время
  • low, не беда, если выполнение немного задержится
  • offscreen,в следующий разrenderвремя илиscrollвыполнить, когда

Задачи с высоким приоритетом (например, ввод с клавиатуры) могут прерывать задачи с низким приоритетом (например,diff) выполняется для более быстрого вступления в силу.

Fiber ReconcilerВ процессе выполнения он будет разделен на 2 этапа:

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

Фаза 1 может быть прервана, позволяя выполнять задачи с более высоким приоритетом в первую очередь, что значительно снижает вероятность пропуска кадров страницы на уровне фреймворка.

Fiberспециальность:

  • Приостановить работу и вернуться к ней позже
  • Может расставлять приоритеты для разных видов работы
  • Повторное использование ранее выполненной работы
  • Завершить работу, которая больше не нужна

Четыре,FiberДерево

Fiber Reconcilerна первом этапеDiffПри расчете аFiberДерево. это деревоVirtual DOMОн генерируется путем добавления дополнительной информации на основе дерева, которое по сути представляет собой связанный список.

FiberДеревья генерируются по одному при первом рендеринге. позже нужноDiff, на основе существующего дерева и последнихVirtual DOMинформации, генерировать новое дерево, и каждый раз, когда новое дерево генерирует новый узел, оно будет возвращать управление основному потоку, чтобы проверить, есть ли задачи с более высоким приоритетом, которые необходимо выполнить. Если нет, продолжайте процесс построения дерева:

Если в процессе есть задача с более высоким приоритетом, которую необходимо выполнить, тоFiber ReconcilerГенерируемое дерево будет отброшено, и оно будет выполнено снова, когда оно будет бездействовать.

в разработкеFiberв процессе дерева,Fiber ReconcilerИнформация об узле, которую необходимо обновить, будет сохранена вEffect ListСреди них, когда выполняется второй этап, соответствующие узлы будут обновляться пакетами.

Фаза выполнения волокна

Каждый рендер состоит из двух фаз:Reconciliation(координацияrender) стадия иCommit(совершить) этап

  • координацияrenderСтадия: можно рассматривать какDiffэтап, этот этап можно прервать, на этом этапе будут обнаружены все изменения узла, такие как добавление узла, удаление и т. д., эти изменения находятся вReactназывается вEffect(побочный эффект)
  • Этап фиксации: выполнение побочных эффектов, рассчитанных на предыдущем этапе, которые необходимо обработать за один раз. Эта стадия не может быть прервана и должна выполняться синхронно одновременно.

Сводка по волокну

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

V. Резюме

нас从React V15Исходя из существующих проблем, введениеReact Fiberидеи решения проблем и представляетFiber Reconcilerрабочий процесс. отStack ReconcilerприбытьFiber Reconciler, на исходном уровне рекурсия заменена на цикл, что решает проблемуReact V15существующие проблемы.

Шесть, анализ исходного кода

scheduler

существуетReact16.5 тогда поставьschedulerОтправьте посылку самостоятельно, просто позвонитеscheduler

scheduleCallbackWithExpirationTime

АсинхронныйrootПланирование задач осуществляется с помощью этого метода.Самое главное здесь - вызватьschedulerизscheduleDeferredCallbackметод (вschedulerпакетschedulework) функция обратного вызова входящего событияperformAsyncWork, и содержащийtimeoutОбъект события тайм-аута

function scheduleCallbackWithExpirationTime(
  root: FiberRoot,
  expirationTime: ExpirationTime,
) {
  if (callbackExpirationTime !== NoWork) {
    // A callback is already scheduled. Check its expiration time (timeout).
    if (expirationTime > callbackExpirationTime) {
      // Existing callback has sufficient timeout. Exit.
      return
    } else {
      if (callbackID !== null) {
        // Existing callback has insufficient timeout. Cancel and schedule a
        // new one.
        cancelDeferredCallback(callbackID)
      }
    }
    // The request callback timer is already running. Don't start a new one.
  } else {
    startRequestCallbackTimer()
  }

  callbackExpirationTime = expirationTime
  const currentMs = now() - originalStartTimeMs
  const expirationTimeMs = expirationTimeToMs(expirationTime)
  const timeout = expirationTimeMs - currentMs
  // 最主要的就是调用了scheduler的scheduleDeferredCallback方法
  callbackID = scheduleDeferredCallback(performAsyncWork, { timeout })
}

scheduler.scheduleWork

Создайте узел планировщикаnewNode, и следуйтеtimeoutAtпорядок добавления вCallbackNodeсвязанный список, звонитеensureHostCallbackIsScheduledздесьexpirationTimeпередается при вызовеtimeoutAtДобавьте время истечения, сформированное текущим временем.

function unstable_scheduleCallback(callback, deprecated_options) {
  var startTime =
    currentEventStartTime !== -1 ? currentEventStartTime : getCurrentTime()

  var expirationTime
  if (
    typeof deprecated_options === 'object' &&
    deprecated_options !== null &&
    typeof deprecated_options.timeout === 'number'
  ) {
    // FIXME: Remove this branch once we lift expiration times out of React.
    expirationTime = startTime + deprecated_options.timeout
  } else {
    // 这里是以后把`expirationTime`从React中抽离出来之后的逻辑
  }

  var newNode = {
    callback,
    priorityLevel: currentPriorityLevel,
    expirationTime,
    next: null,
    previous: null,
  }

  // Insert the new callback into the list, ordered first by expiration, then
  // by insertion. So the new callback is inserted any other callback with
  // equal expiration.
  if (firstCallbackNode === null) {
    // This is the first callback in the list.
    firstCallbackNode = newNode.next = newNode.previous = newNode
    // 调用ensureHostCallbackIsScheduled
    ensureHostCallbackIsScheduled()
  } else {
    var next = null
    var node = firstCallbackNode
    do {
      if (node.expirationTime > expirationTime) {
        // The new callback expires before this one.
        next = node
        break
      }
      node = node.next
    } while (node !== firstCallbackNode)

    if (next === null) {
      // No callback with a later expiration was found, which means the new
      // callback has the latest expiration in the list.
      next = firstCallbackNode
    } else if (next === firstCallbackNode) {
      // The new callback has the earliest expiration in the entire list.
      firstCallbackNode = newNode
      ensureHostCallbackIsScheduled()
    }

    var previous = next.previous
    previous.next = next.previous = newNode
    newNode.next = next
    newNode.previous = previous
  }

  return newNode
}

ensureHostCallbackIsScheduled

Если обратный вызов уже вызывается, тоreturn, потому что его продолжали бы называть,isExecutingCallbackсуществуетflushWorkбудет изменен наtrue. еслиisHostCallbackScheduledдляfalse, то есть планирование еще не началось, то установитеtrue, если он уже начался, отмените его напрямую, потому что порядок может измениться. передачаrequestHostCallbackНачать планирование здесь

function ensureHostCallbackIsScheduled() {
  if (isExecutingCallback) {
    // Don't schedule work yet; wait until the next time we yield.
    return
  }
  // Schedule the host callback using the earliest expiration in the list.
  var expirationTime = firstCallbackNode.expirationTime
  if (!isHostCallbackScheduled) {
    isHostCallbackScheduled = true
  } else {
    // Cancel the existing host callback.
    cancelHostCallback()
  }
  requestHostCallback(flushWork, expirationTime)
}

cancelHostCallback = function() {
  scheduledHostCallback = null
  isMessageEventScheduled = false
  timeoutTime = -1
}

requestHostCallback

Начните вводить расписание, установите содержание расписания, используйтеscheduledHostCallbackа такжеtimeoutTimeЭти две глобальные переменные записывают функцию обратного вызова и соответствующее время истечения срока действия.

передачаrequestAnimationFrameWithTimeout, который на самом деле вызываетrequestAnimationFrameплюс установить100msтаймер для предотвращенияrequestAnimationFrameслишком долго для срабатывания.

обратный звонокanimationTickи установитьisAnimationFrameScheduledГлобальная переменнаяtrue

requestHostCallback = function(callback, absoluteTimeout) {
  scheduledHostCallback = callback
  timeoutTime = absoluteTimeout
  if (isFlushingHostCallback || absoluteTimeout < 0) {
    // Don't wait for the next frame. Continue working ASAP, in a new event.
    window.postMessage(messageKey, '*')
  } else if (!isAnimationFrameScheduled) {
    isAnimationFrameScheduled = true
    requestAnimationFrameWithTimeout(animationTick)
  }
}

фиктивный запросIdleCallback

потому чтоrequestIdleCallbackэтоAPIОн все еще находится в стадии черновика, поэтому скорость реализации браузера невысока, так что вот онReactиспользуется напрямуюpolyfillстроить планы.

Эта схема простоrequestAnimationFrameВыполните дополнительную обработку, прежде чем браузер отобразит кадр, затем передайтеpostMessageсуществуетmacro task(аналогичныйsetTimeout) для добавления обратного вызова, потому что дальше браузер перейдет к этапу рендеринга, поэтому вызывается основной потокblockжизнь,Обратный вызов, когда основной поток свободен

animationTick

если толькоscheduledHostCallbackПродолжай звонитьrequestAnimationFrameWithTimeoutПоскольку этот кадр визуализируется, очередь не может быть очищена, и она будет вызвана снова, поэтому здесь она опущена.requestHostCallbackНеобходимость призыва

Следующий фрагмент кода используется для вычисления разделенияrequestAnimationFrameразница во времени, если эта разница во времени меньше текущей два раза подрядactiveFrameTime, что указывает на то, что частота кадров платформы очень высока. В этом случае время кадра будет динамически уменьшаться.

последнее обновлениеframeDeadline, то если нет триггераidleTickзатем отправьте сообщение

var animationTick = function(rafTime) {
  if (scheduledHostCallback !== null) {
    requestAnimationFrameWithTimeout(animationTick)
  } else {
    isAnimationFrameScheduled = false
    return
  }

  var nextFrameTime = rafTime - frameDeadline + activeFrameTime
  if (nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime) {
    if (nextFrameTime < 8) {
      nextFrameTime = 8
    }
    activeFrameTime =
      nextFrameTime < previousFrameTime ? previousFrameTime : nextFrameTime
  } else {
    previousFrameTime = nextFrameTime
  }
  frameDeadline = rafTime + activeFrameTime
  if (!isMessageEventScheduled) {
    isMessageEventScheduled = true
    window.postMessage(messageKey, '*')
  }
}

idleTick

Судите первымpostMessageЭто ваш собственный, а не возврат напрямую

пустойscheduledHostCallbackа такжеtimeoutTime

Получить текущее время, сравнитьframeDeadline, проверьте, истекло ли время ожидания, если время ожидания истекло, оцените задачуcallbackДостигнут ли срок годности, если нет, перепроверьте этоcallbackСделайте отправку, затем вернитесь. Если он придет, установитеdidTimeoutдляtrue

Далее стоит позвонитьcallback, вот настройкаisFlushingHostCallbackГлобальная переменнаяtrueПредставитель выполняет. и позвониcallbackто естьflushWorkи пройти вdidTimeout

var idleTick = function(event) {
  if (event.source !== window || event.data !== messageKey) {
    return
  }

  isMessageEventScheduled = false

  var prevScheduledCallback = scheduledHostCallback
  var prevTimeoutTime = timeoutTime
  scheduledHostCallback = null
  timeoutTime = -1

  var currentTime = getCurrentTime()

  var didTimeout = false
  if (frameDeadline - currentTime <= 0) {
    if (prevTimeoutTime !== -1 && prevTimeoutTime <= currentTime) {
      didTimeout = true
    } else {
      if (!isAnimationFrameScheduled) {
        isAnimationFrameScheduled = true
        requestAnimationFrameWithTimeout(animationTick)
      }
      scheduledHostCallback = prevScheduledCallback
      timeoutTime = prevTimeoutTime
      return
    }
  }

  if (prevScheduledCallback !== null) {
    isFlushingHostCallback = true
    try {
      prevScheduledCallback(didTimeout)
    } finally {
      isFlushingHostCallback = false
    }
  }
}

flushWork

установить первымisExecutingCallbackдляtrue, представляющий призваниеcallback

настраиватьdeadlineObject.didTimeout,существует ReactЕго можно использовать в бизнесе, чтобы определить, истекло ли время ожидания задачи.

еслиdidTimeout, будет один раз изfirstCallbackNodeВыполнять в обратном порядке до первой задачи с неистекшим сроком действия

Если таймаута нет, то выполнить первыйcallback, до конца времени кадра

Наконец, очистите переменную, если задача не завершена, вызовите ее снова.ensureHostCallbackIsScheduledввести расписание

КстатиImmediaПриоритетные задачи вызываются снова.

function flushWork(didTimeout) {
  isExecutingCallback = true
  deadlineObject.didTimeout = didTimeout
  try {
    if (didTimeout) {
      while (firstCallbackNode !== null) {
        var currentTime = getCurrentTime()
        if (firstCallbackNode.expirationTime <= currentTime) {
          do {
            flushFirstCallback()
          } while (
            firstCallbackNode !== null &&
            firstCallbackNode.expirationTime <= currentTime
          )
          continue
        }
        break
      }
    } else {
      if (firstCallbackNode !== null) {
        do {
          flushFirstCallback()
        } while (
          firstCallbackNode !== null &&
          getFrameDeadline() - getCurrentTime() > 0
        )
      }
    }
  } finally {
    isExecutingCallback = false
    if (firstCallbackNode !== null) {
      ensureHostCallbackIsScheduled()
    } else {
      isHostCallbackScheduled = false
    }
    flushImmediateWork()
  }
}

flushFirstCallback

то, что он делает, просто

  • Если в текущей очереди есть только один обратный вызов, очистить очередь
  • Вызовите обратный вызов и передайтеdeadlineобъект, имеющийtimeRemainingметод переданframeDeadline - now()определить, наступило ли время кадра
  • Если обратный вызов имеет возвращаемое содержимое, добавьте этот возврат в очередь обратного вызова.

ссылка на глобальную переменную

isHostCallbackScheduled

Начато ли планирование, вensureHostCallbackIsScheduledУстановить какtrue, в конце выполненияcallbackа затем установить наfalse

scheduledHostCallback

существуетrequestHostCallbackзначение, как правило,flushWork, который представляет следующее запланированное действие

isMessageEventScheduled

был ли отправлен вызовidleTickновости, вanimationTickустановлен вtrue

timeoutTime

Указывает время просроченной задачи, вidleTickУстанавливается, когда обнаруживается, что время выполнения первой задачи истекло

isAnimationFrameScheduled

начал звонитьrequestAnimationFrame

activeFrameTime

Время рендеринга кадра, по умолчанию 33, то есть 30 кадров в секунду.

frameDeadline

Запишите время истечения текущего кадра, равноеcurrentTime + activeFraeTime, то есть,requestAnimationFrameОбратный вызов входящего времени плюс время одного кадра.

isFlushingHostCallback

Это выполняетсяcallback

Справочная документация:Как работает React Fiber и связанные с ним концепции

приложение:

1. Каковы болевые точки React15? Что такое клетчатка? Почему React16 нужно представить Fiber?

  • визуализировать иdiffЭтапы выполняются за один раз, и страница застрянет, когда дерево узлов огромно.
  • Fiberне таинственно, простоVirtual-DOMпревратился в链表结构
  • Структура связанного спискаrequestIdleCallbackМожет реализовать прерываемый и восстанавливаемый механизм планирования

2. Виртуальный DOM в React16 такой же, как в React15.

3. Как реализовать структуру данных и алгоритм обхода Fiber?

  • Reactиспользуя связанный список вVirtual DOMсвязаны, каждый узел представляет собойFiber

4. Как реализовать прерываемое и возобновляемое планирование задач в архитектуре Fiber?

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

5. Как реализовать рендеринг компонентов и сбор и отправку побочных эффектов в архитектуре Fiber?

  • Выполняемый порядок сбора аналогичен предварительному обходу двоичного дерева.
  • Завершенный порядок сбора аналогичен обходу двоичного дерева в обратном порядке.

6. Как реализовать стратегию оптимизации согласования и двойной буферизации в Fiber?

  • существуетFiberдобавить один в структуруalternateИдентификатор поля отображался последнимFiberдерево, повторно используемое для следующего рендера

Выше это то, что яFiberПоверхностное понимание, если есть какие-либо ошибки, пожалуйста, поправьте меня~~~