Это, пожалуй, самый распространенный способ открыть React Fiber (разрезка по времени)

внешний интерфейс JavaScript React.js
Это, пожалуй, самый распространенный способ открыть React Fiber (разрезка по времени)

Написать статью о React Fiber, этот Флаг установлен давно, и это одна из целей этого года. Недавняя статья о «Наггетс» получила много внимания и поддержки, что дало мне большую мотивацию, поэтому я решил написать ее хорошо. Объясню самым популярным образом, так что это научно-популярная статья. Независимо от того, используете ли вы React или Vue, идеи здесь заслуживают изучения!



Ежегодный весенний фестиваль реагирует:React ConfКак только вы придете, я не знаю, какие там будут сюрпризы, в прошлом году — React Hooks, в предыдущем — React Fiber… Я должен опубликовать эту статью до React Conf:

  • 😲React Fiber существует так долго, что эта статья — старое вино в новой бутылке? Для себя, благодаря этой статье заново познакомился с React Fiber, это не новинка, это тоже старое вино в новой бутылке, если не верите, просто прочитайте...

  • 🆕React Fiber — это не новинка, но первое широко известное приложение в области фронтенда..

  • Бамбукпонять, что он делает? Код React Fiber очень сложен и порог высок, вы его не понимаете, и вы можете не понять новую Killer Feature React позже.

  • 🤥Разве я не обновился до React v16?? Чтобы по-настоящему оценить эффект рефакторинга React Fiber, может быть, в следующем месяце, может быть, до версии 17. v16 — это всего лишь переходная версия, то есть текущий React все еще рендерится синхронно, и он подпрыгивает, это не значит, что он выйдет во втором квартале этого года??

  • 😁Извините, я случайно написал это немного длинно, вы можете прочитать это как роман, код весь псевдокод


Краткое содержание статьи ниже



Однопроцессорное планирование: оптические волокна — не новость


Этот черный интерфейс должен быть MicrosoftDOSоперационная система


МайкрософтDOSЯвляется单任务操作系统, также известная как «симплексная операционная система». Эта операционная система позволяет одновременно запускать только одну программу.invalid sсуществует«Как люди запускали несколько программ в эпоху отсутствия графического интерфейса (только текстовый интерфейс)? 》ответ относится к этому как: '«Отключенная» операционная система без планирования задач вообще'.

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

До Windows 3.x у него был настоящий планировщик процессов, реализующий одновременное выполнение нескольких процессов.

Обратите внимание, что параллелизм и параллелизм — это не одно и то же.


Современные операционные системы являютсямногозадачная операционная система, Если политика планирования процесса разделена в соответствии с количеством ядер ЦП, ее можно разделить наОднопроцессорное планированиеа такжеМногопроцессорное планирование.本文只关注的是单处理器调度,因为它可以类比JavaScript的运行机制。

🔴Грубо говоря, чтобы реализовать параллелизм процессов, операционная система будет распределять права выполнения ЦП на несколько процессов в соответствии с определенной стратегией планирования, и несколько процессов имеют возможность выполняться, и пусть они выполняются поочередно, формируя иллюзию «одновременного запуска», потому что процессор настолько быстр, что люди его вообще не чувствуют. Фактически, в одноядерной физической среде одновременно может работать только одна программа..


Это напоминает мне технику клонирования в «Жемчуге дракона» (я видел ее в детстве, не брызгайте, если скажу неправильно), это по сути человек, но он двигается слишком быстро и выглядит как клон. называетсяПараллельно(один процессор).



Напротив, аватары в Наруто существуют физически, и они действительно могут выполнять несколько задач одновременно.параллельно(Строго говоря, этоMaster-SlaveАрхитектура, хотя аватар и существует физически, у него не должно быть самостоятельной воли).

так🔴 Параллелизм может быть параллельным, но параллелизм не обязательно является параллельным. Они не могут быть равными. Параллелизм обычно требует поддержки на физическом уровне.. Роб Пайк, отец Go, выступил с очень известным докладом о конкурентности и параллелизме.Concurrency is not parallelism


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


0️⃣ В порядке живой очереди (FCFS)

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

FCFSнадDOSОднозадачная ОС не имеет большого значения. Так что это очень легко понять, ведь жизнь полна таких примеров: .

  • Пара FCFS短进程неблагоприятный. Короткий процесс — это процесс с очень коротким временем выполнения, его можно сравнить с очередями в столовой:В очереди за едой в столовой больше всего раздражают люди, которые сами упаковывают несколько блюд.长进程Точно так же он занимает ресурсы ЦП, и люди, которые стоят в очереди только на один заказ, будут чувствовать себя в невыгодном положении, а те, кто заказывает один заказ, будут чувствовать, что их приоритет должен быть выше, ведь они занимают очень мало времени. , в любом случае, вы упаковываете так много заказов, а затем ждете. Это нормально какое-то время, зачем заставлять так много людей ждать позади вас так долго...

  • Пара FCFSI/O密集неблагоприятный. Процессы с интенсивным вводом-выводом (здесь синхронный ввод-вывод) будут блокировать спящий режим при выполнении операций ввода-вывода, что приведет к тому, что процесс будет возвращен в очередь готовности в ожидании следующей услуги. Его можно сравнить с отделом ZF по ведению бизнеса:Предположим, одно окно для процессора и одно окно для ввода-вывода. Вы, наконец, поставлены в очередь в окне ЦП. В это время вы обнаружите, что один из них не соответствует условиям или отсутствует. Вам нужно перейти в окно ввода-вывода. Хорошо, перейдите в окно ввода-вывода, чтобы поставить в очередь. После выполнение ввода-вывода завершено, вы должны перезапустить окно ЦП. Это несправедливо по отношению к этим людям, которые теряют все...

Таким образом, исходная стратегия FCFS не популярна при планировании однопроцессорных процессов.


1️⃣ Повернуть

Это часы на основеПревентивная стратегия, которая также является самой простой из стратегий упреждения:Справедливо дайте каждому процессу определенное время выполнения.Когда время исчерпано или заблокировано, операционная система назначит другим процессам приоритетное право на выполнение..

режим принятия решения: 抢占策略соответствующий非抢占策略, неупреждающая стратегия относится к тому, чтобы позволить процессу работать до конца, блокировать (например, ввод-вывод или спящий режим) или активно передавать управление; упреждающая стратегия поддерживает прерывание запущенного процесса и удерживает инициативу в операционной системе, но обычно стоимость будет выше.

Суть этой стратегии планирования заключается в следующем.Определение подходящей длины временного интервала: Слишком длинные, длительные процессы слишком долго занимают ресурсы, другие процессы не получат ответа (слишком долгое ожидание выполнения), далее аналогично предыдущемуFCFSРазницы нет, слишком короткий нехороший, потому что вытеснение процесса и переключение обходятся дорого, а стоимость не мала.Если временной интервал слишком короткий, время может быть потрачено впустую на переключение контекста, в результате чего процесс не сможет выполнить ничего практичного.

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

Стратегию ротации очень легко понять, но определить продолжительность интервала времени может быть немного сложно; иFCFSТочно так же стратегия циклического перебора по-прежнему несправедлива по отношению к процессу ввода-вывода.


2️⃣ Далее по кратчайшему процессу (SPN)

сказано выше先到先得пара стратегий短进程несправедливый,最短进程优先Просто позвольте самому короткому процессу выполниться первым, то есть:Процессы расставляются по приоритетам в соответствии с предполагаемым временем их выполнения, и короткие процессы выполняются первыми, а затем длинные процессы. Это непревентивная стратегия.

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

SPNНедостаток: если в системе большое количество коротких процессов, то длинный процесс может зависнуть и не отвечать.

Кроме того, поскольку это не упреждающая стратегия, хотя короткие процессы теперь могут получить больше возможностей для выполнения, это все равно не решает проблему.FCFSПроблема: как только длительный процесс получает ресурсы ЦП, ему приходится ждать завершения своего выполнения, что приводит к отсутствию ответа от последующих процессов.


3️⃣ минимальное оставшееся время (Shortest Remaining Time, SRT)

SRT и дальнейшая оптимизация SPN, увеличение вытеснения. На основе SPN при добавлении процесса в очередь готовности операционная система сравниваетТолько что добавлен новый процесса такжеСтарый процесс, который в настоящее время выполняетсяЕсли оставшееся время нового процесса короче, новый процесс вытеснит старый процесс.

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


4️⃣ Приоритет наивысшего коэффициента отклика (HRRN)

Чтобы решить проблему длительного голодания процесса, при этом улучшив скорость отклика процесса. Есть еще одно最高响应比优先的Стратегия, сначала поймите, что такое коэффициент отклика:

响应比 = (等待执行时间 + 进程执行时间) / 进程执行时间

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

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

5️⃣ Способ обратной связи

Все SPN, SRT и HRRN должны оценивать и подсчитывать время процесса, что сложно реализовать и требует определенных накладных расходов. Метод обратной связиобратная связь постфактумПуть. В рамках этой стратегии:Каждый процесс имеет одинаковый приоритет в начале, и каждый раз, когда он вытесняется (необходимо использовать в сочетании с другими стратегиями вытеснения, такими как циклический перебор), приоритет будет уменьшаться на один уровень. Поэтому обычно он делит несколько очередей на основе приоритета.

Например:

队列1
队列2
...
队列N

Будут добавлены новые задачи队列1,队列1последует轮转策略Запланировано в единицах кванта времени. Короткий процесс может быстро получить ответ, в то время как длинный процесс может не обработаться за квант времени, и он будет вытеснен и поставлен в очередь.队列2.

队列2Будет в队列1Задачи выполняются после очистки.Иногда очереди с низким приоритетом могут долго ждать выполнения, поэтому обычно дается некоторая компенсация, например увеличение времени выполнения, поэтому队列2Длина временного интервала циклического перебора равна 2.

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



Не существует универсальной стратегии планирования, она должна учитывать множество факторов:

  • Скорость отклика. Время ожидания выполнения процесса
  • справедливость. Учитывайте короткие процессы, длинные процессы и процессы ввода/вывода

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

Вышеизложенных знаний достаточно для этой статьи.Алгоритм планирования процессов реальной операционной системы намного сложнее того, что сказано в учебнике.Заинтересованные читатели могут его изучить.LinuxСуществует также много информации о связанных алгоритмах планирования процессов, таких как«Разработка и эволюция стратегий планирования процессов Linux».



Аналогия со средой выполнения JavaScript в браузере


JavaScript похож на улицу с односторонним движением


JavaScript этооднопоточная операцияДа и в среде браузера много дерьма, он отвечает за парсинг и выполнение JS, отрисовку, обработку событий, загрузку статического ресурса и обработку страницы, эти задачи могут быть аналогичны вышеописанному «процессу».

В частности, это относится к движку Javascript, работающему в одном потоке. Строго говоря, движок Javascript и движок рендеринга страниц находятся в одном и том же месте.渲染线程, рендеринг графического интерфейса пользователя и выполнение Javascript являются взаимоисключающими.Кроме того, базовая операция асинхронного ввода-вывода может фактически управляться несколькими потоками.

Источник изображения:Rendering Performance

Это просто «JavaScript», который может делать только одну вещь за раз, это иDOSКак и в однозадачной операционной системе, все можно делать только одно за другим. Если впереди тупая задача, которая надолго занимает ЦП, а потом ничего нельзя сделать, браузер зависнет, а пользовательский опыт будет очень плохим..


Для «интерфейсного фреймворка» есть три направления решения этой проблемы.:

  • 1️⃣ Оптимизируйте каждую задачу, чтобы сделать ее максимально быстрой. Сжимайте операции ЦП
  • 2️⃣ Быстро отвечайте пользователям, чтобы пользователи чувствовали себя достаточно быстро, чтобы не блокировать взаимодействие с пользователем.
  • 3️⃣ Попробуйте рабочую многопоточность

Vue выбирает первый ️⃣, потому что для Vue, используйте模板У него есть много возможностей для оптимизации, а благодаря адаптивному механизму Vue может точно обновлять узлы, читатели могут посмотретьВыступление Ю Юйси на Vue Conf в этом году, отлично!; а React выбрал 2️⃣ . Некоторые люди также пробовали многопоточную схему рендеринга Worker, и довольно сложно обеспечить согласованность состояния и представления.


Почему React представил архитектуру Fiber? Взгляните на диаграмму пламени ниже, которая представляет собой список потребления ресурсов рендеринга в React V15. Весь рендеринг занял 130 мс,🔴 В этом React будет рекурсивно сравнивать дерево VirtualDOM, находить узлы, которые необходимо изменить, а затем обновлять их синхронно, за один раз. Этот процесс React называетсяReconcilation(китайский можно перевести как协调).



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

Таким образом, вы, возможно, не сможете испытать это, но через следующие две картинки испытать (Источник изображения:Dan AbramovизBeyond React 16Выступление,рекомендую к просмотру👍.Также большое спасибобледныйположитьПодобные демонстрации размещены в CodeSandbox.На 🎉 каждый испытывает это сам):


Реагировать в синхронном режиме:


оптимизированныйConcurrentРеагировать в режиме:


Согласование React — это операция с интенсивным использованием ЦП, что эквивалентно «долгому процессу», о котором мы упоминали выше. Следовательно, исходное намерение такое же, как и при планировании процессов: мы должны позволить высокоприоритетным процессам или коротким процессам запускаться первыми и не позволять длинным процессам занимать ресурсы в течение длительного времени.

Так как же оптимизирован React? фокус,🔴Чтобы создать «иллюзию» того, что приложение работает быстро, мы не можем позволить программе занимать ресурсы в течение длительного времени.Вы можете использовать браузерный рендеринг, макет, рисование, загрузку ресурсов (например, парсинг HTML), ответ на событие, выполнение сценария В качестве «процесса» операционной системы нам необходимо разумно распределять ресурсы ЦП с помощью некоторых стратегий планирования, тем самым повышая скорость отклика пользователя в браузере, принимая во внимание эффективность выполнения задачи..


🔴Поэтому React использует архитектуру Fiber, чтобы сделать собственный процесс согласования прерываемым. «Своевременный» отказ от прав на выполнение ЦП имеет и другие преимущества, помимо того, что позволяет браузеру своевременно реагировать на действия пользователя.:


Вот почему React нуждается в Fiber 😏.


Что такое клетчатка

Для React Fiber может понимать с двух точек зрения:


1. Примитив управления потоком

Волокно, также называемоесопрограмма, или волокна. Впервые я столкнулся с этой концепцией, когда изучал Ruby, а Ruby называл сопрограммы Fiber. Позже выяснилось, что подобные механизмы есть во многих языках, например, в Lua.Coroutine, а также более знакомые фронтенд-разработчикамES6добавленGenerator.

Эта статья не запутанаProcesses, threads, green threads, protothreads, fibers, coroutines: what's the difference?

🔴 На самом деле корутины и треды не одно и то же, сами корутины не имеют параллелизма или параллелизма (нужно взаимодействовать с тредами), это всего лишь механизм отказа от управления процессом. Чтобы понять сопрограммы, надо смотреть на них вместе с обычными функциями, на примере Генератора:

Во время выполнения обычных функций невозможнопрервано и возобновлено:

const tasks = []
function run() {
  let task
  while (task = tasks.shift()) {
    execute(task)
  }
}

а такжеGeneratorМогу:

const tasks = []
function * run() {
  let task

  while (task = tasks.shift()) {
    // 🔴 判断是否有高优先级事件需要处理, 有的话让出控制权
    if (hasHighPriorityEvent()) {
      yield
    }

    // 处理完高优先级事件后,恢复函数调用栈,继续执行...
    execute(task)
  }
}

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


Итак, теперь у вас должны быть следующие вопросы:

  • 1️⃣ В браузере нет условий вытеснения, поэтому React может использовать только механизм yield?
  • 2️⃣ Как определить, что есть первоочередные задачи, которыми нужно заняться, то есть когда отпустить?
  • 3️⃣ React Тогда почему бы не использовать Генератор?


A1️⃣: Правильно, взять на себя инициативу отказаться от механизма

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

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

Это «контрактное» планирование, которое требует, чтобы наша программа и браузер были тесно интегрированы и доверяли друг другу.. Например, нам могут быть назначены интервалы времени выполнения браузером (черезrequestIdleCallbackРеализация, которая будет представлена ​​ниже), мы должны завершить выполнение за это время, как и было оговорено, и вернуть управление браузеру.


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

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




A2️⃣: API requestIdleCallback

в примере кода вышеhasHighPriorityEvent()В текущем браузере это невозможно, у нас нет возможности определить, есть ли в данный момент задачи с более высоким приоритетом, ожидающие выполнения.

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

Например, чтобы представление работало плавно, вы можете разделить временные срезы с минимальной воспринимаемой человеком скоростью 60 кадров в секунду, чтобы каждый временной срез составлял 16 мс.

На самом деле браузер предоставляет соответствующий интерфейс —requestIdleCallbackAPI:

window.requestIdleCallback(
  callback: (dealine: IdleDeadline) => void,
  option?: {timeout: number}
  )

IdleDeadlineИнтерфейс выглядит следующим образом:

interface IdleDealine {
  didTimeout: boolean // 表示任务执行是否超过约定时间
  timeRemaining(): DOMHighResTimeStamp // 任务可供执行的剩余时间
}

От одного имени,requestIdleCallbackозначаетПозвольте браузеру выполнить наш обратный вызов, когда он «свободен». Этот обратный вызов пройдет в срок, указывающий, сколько времени у браузера есть для нас для выполнения. Чтобы не затягивать, нам лучше завершить выполнение в течение этого периода времени..


Когда браузер бесплатный?

Давайте сначала посмотрим, что браузер может делать во фрейме (Frame, который можно считать циклом цикла событий):

Вы можете открыть вкладку «Производительность» инструментов разработчика Chrome, где можно подробно посмотреть, какая задача (Task) выполняется в каждом кадре Javascript, и сколько времени затрачено.


Источник изображения:requestIdleCallback, который вы должны знать

Браузер может выполнять следующие задачи во фрейме, и порядок их выполнения в основном фиксирован:

  • Обработка событий пользовательского ввода
  • Выполнение Javascript
  • запросанимационный вызов
  • Макет
  • краска

Идеальное время кадра16ms(1000мс/60), если браузер закончил обработку вышеперечисленных задач (после верстки и отрисовки), и еще есть лишнее время, браузер вызоветrequestIdleCallbackПерезвоните. Например



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

Кроме того, не рекомендуетсяrequestIdleCallbackв ходе выполненияDOMоперации, так как это может привести к перерасчету или изменению макета стилей (например, вызов сразу после манипулирования DOMgetBoundingClientRect), это время трудно предсказать, и это может привести к тайм-ауту выполнения обратного вызова и пропуску кадров.


В настоящее времяrequestIdleCallbackВ настоящее время поддерживается только Chrome. Итак, в настоящее время Reactпонял один. он используетMessageChannelМоделирование задерживает обратный вызов для выполнения после «операции рисования»:



Просто посмотрите на код
const el = document.getElementById('root')
const btn = document.getElementById('btn')
const ch = new MessageChannel()
let pendingCallback
let startTime
let timeout

ch.port2.onmessage = function work()  {
  // 在绘制之后被执行
  if (pendingCallback) {
    const now = performance.now()
    // 通过now - startTime可以计算出requestAnimationFrame到绘制结束的执行时间
    // 通过这些数据来计算剩余时间
    // 另外还要处理超时(timeout),避免任务被饿死
    // ...
    if (hasRemain && noTimeout) {
      pendingCallback(deadline)
    }
  }
}

// ...

function simpleRequestIdleCallback(callback, timeout) {
  requestAnimationFrame(function animation() {
    // 在绘制之前被执行
    // 记录开始时间
    startTime = performance.now()
    timeout = timeout
    dosomething()
    // 调度回调到绘制结束后执行
    pendingCallback = callback
    ch.port1.postMessage('hello')
  })
}

приоритет задачи

Как упоминалось выше, во избежание голодания задачи может быть установлен тайм-аут.Этот тайм-аут не мертв, задачи с низким приоритетом могут ждать медленно, а задачи с высоким приоритетом должны выполняться в первую очередь.В настоящее время React имеет предопределенные 5 приоритетов, которые я также представил в ["Разговоры о механизме событий React и будущем (реагирование-события)"]:

  • Immediate(-1) - задачи данного приоритета будут выполняться синхронно, либо должны выполняться немедленно и не могут быть прерваны
  • UserBlocking(250 мс) Эти задачи обычно являются результатом взаимодействия с пользователем и требуют немедленной обратной связи.
  • Normal(5s) Реагируйте на задачи, которые не нужно ощущать немедленно, например на сетевые запросы.
  • Low(10s) Эти задачи могут быть поставлены позже, но в конечном итоге должны быть выполнены.Например уведомления об анализе
  • Idle(без тайм-аута) некоторые ненужные задачи (например, скрытый контент), могут умереть от голода



A3️⃣: Слишком много проблем

официальный в«Принципы волокна: вклад в волокно»тоже ответил. Есть две основные причины:

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

Приведенное выше понимание может отличаться, рекомендуется прочитать исходный текст

Возможно, вы этого не поняли.Просто React пытался реализовать это с помощью Generator, но позже нашел это очень хлопотным и сдался.



2. Исполнительный блок

Другая интерпретация волокна - «волокно»:Это структура данных или исполнительный блок. Нам все равно, как выглядит эта структура данных,🔴 Думайте об этом как об исполнительной единице, каждый раз, когда выполняется «исполнительная единица», React проверяет, сколько времени осталось, и если времени нет, он отказывается от управления.


Как упоминалось выше, React не использует механизм yield уровня языка/синтаксиса Generator, но реализует свой собственный механизм yield планирования. Этот механизм основан на исполнительном блоке «Fiber», и его процесс выглядит следующим образом:

Предположим, пользователь звонитsetStateОбновите компонент, задача для обновления сначала будет поставлена ​​в очередь, а затем пройденаrequestIdleCallbackЗапросить отправку браузера:

updateQueue.push(updateTask);
requestIdleCallback(performWork, {timeout});

Теперь браузер простаивает или время ожидания истекло, и он будет вызванperformWorkвыполнить задание:

// 1️⃣ performWork 会拿到一个Deadline,表示剩余时间
function performWork(deadline) {

  // 2️⃣ 循环取出updateQueue中的任务
  while (updateQueue.length > 0 && deadline.timeRemaining() > ENOUGH_TIME) {
    workLoop(deadline);
  }

  // 3️⃣ 如果在本次执行中,未能将所有任务执行完毕,那就再请求浏览器调度
  if (updateQueue.length > 0) {
    requestIdleCallback(performWork);
  }
}

workLoopКак вы, наверное, догадались, он будет вызывать задачи обновления из очереди обновлений (updateQueue) для выполнения, и каждый раз, когда '执行单元', просто проверьте, достаточно ли оставшегося времени, если достаточно, выполните следующий执行单元, в противном случае остановите выполнение, сохраните сцену и восстановите ее, когда у вас будет право на выполнение в следующий раз:


// 保存当前的处理现场
let nextUnitOfWork: Fiber | undefined // 保存下一个需要处理的工作单元
let topWork: Fiber | undefined        // 保存第一个工作单元

function workLoop(deadline: IdleDeadline) {
  // updateQueue中获取下一个或者恢复上一次中断的执行单元
  if (nextUnitOfWork == null) {
    nextUnitOfWork = topWork = getNextUnitOfWork();
  }

  // 🔴 每执行完一个执行单元,检查一次剩余时间
  // 如果被中断,下一次执行还是从 nextUnitOfWork 开始处理
  while (nextUnitOfWork && deadline.timeRemaining() > ENOUGH_TIME) {
    // 下文我们再看performUnitOfWork
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork, topWork);
  }

  // 提交工作,下文会介绍
  if (pendingCommit) {
    commitAllWork(pendingCommit);
  }
}

Нарисуйте блок-схему!




React’s Fiber Retrofit

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


1. Настройка структуры данных

Левая сторона — это виртуальный DOM, а правая сторона может рассматриваться как стек рекурсивных вызовов diff.


До упомянутого выше React 16 согласование выполнялось синхронно и рекурсивно. То есть это алгоритм согласования, основанный на функции «стек вызовов», поэтому его часто называютStack Reconcilation, Вы можете просмотреть эту статью«Понимание компонентов React и основ хуков из Preact»Давайте вернемся к истории.


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

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

следовательноСначала нам нужно настроить существующую структуру данных React,模拟函数调用栈, разлагает вещи, которые должны быть обработаны рекурсивно до этого, на инкрементные единицы выполнения и преобразует рекурсию в итерацию.


Текущая практика React заключается в использовании链表, внутри каждого узла VirtualDOM теперь используетсяFiberУказывает, что его структура примерно следующая:

export type Fiber = {
  // Fiber 类型信息
  type: any,
  // ...

  // ⚛️ 链表结构
  // 指向父节点,或者render该节点的组件
  return: Fiber | null,
  // 指向第一个子节点
  child: Fiber | null,
  // 指向下一个兄弟节点
  sibling: Fiber | null,
}

С картинками показать взаимосвязь будет более интуитивно понятно:


Использование структуры связанного списка — это только результат, а не цель.Первоначальная цель разработчиков React состояла в том, чтобы смоделировать стек вызовов.. Об этом упоминается во многих статьях о Fiber Подробное определение стека вызовов см.Wiki:

Стек вызовов чаще всего используется для хранения подпрограмм.обратный адрес. При вызове любой подпрограммы основная программа должна временно хранить адрес, по которому подпрограмма должна вернуться после выполнения. Следовательно, если вызываемая подпрограмма также вызывает другие подпрограммы, ее собственный адрес возврата должен храниться в стеке вызовов, а затем извлекаться после ее собственного выполнения. Помимо обратного адреса, он также сохраняет本地变量,函数参数,环境传递(Scope?)


React Fiber также известен как Virtual Stack Frame, вы можете сравнить его со стеком вызовов функций, эти две структуры очень похожи:

стек вызовов функций Fiber
основная единица функция Виртуальный DOM-узел
войти параметр функции Props
местное государство локальная переменная State
выход возвращаемое значение функции React Element
Нижний уровень Вложенные вызовы функций дочерний узел
Превосходная ссылка обратный адрес родительский узел (возврат)

Волокно, как и фрейм стека вызовов, сохраняет контекстную информацию об обработке узла. Поскольку оно реализовано вручную, оно более управляемо. Мы можем сохранить его в памяти и прервать и возобновить в любое время.


Благодаря этой корректировке структуры данных узлы теперь могут обрабатываться итеративно. приди и посмотриperformUnitOfWork, который на самом деле является обходом в глубину:


/**
 * @params fiber 当前需要处理的节点
 * @params topWork 本次更新的根节点
 */
function performUnitOfWork(fiber: Fiber, topWork: Fiber) {
  // 对该节点进行处理
  beginWork(fiber);

  // 如果存在子节点,那么下一个待处理的就是子节点
  if (fiber.child) {
    return fiber.child;
  }

  // 没有子节点了,上溯查找兄弟节点
  let temp = fiber;
  while (temp) {
    completeWork(temp);

    // 到顶层节点了, 退出
    if (temp === topWork) {
      break
    }

    // 找到,下一个要处理的就是兄弟节点
    if (temp.sibling) {
      return temp.sibling;
    }

    // 没有, 继续上溯
    temp = temp.return;
  }
}

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

Благодаря использованию структуры связанного списка, даже если поток обработки прерывается, мы всегда можем начать с последнего необработанногоFiberпродолжать движение.

Вся последовательность итераций такая же, как и предыдущая рекурсивная, на следующем рисунке предполагается, чтоdiv.appОбновлено:


как тыtext(hello)прерывается, то в следующий раз он начнется сpУзел начинает обработку


Еще одним преимуществом этой настройки структуры данных является то, что, когда некоторые узлы ненормальны, мы можем распечатать полный «стек узлов», просто следуя инструкциям.returnВозврат можно сделать.



2. Двухэтапный сплит



Если вы сейчас используете последнюю версию React (v16) с помощью инструмента производительности Chrome, совершенно очевидно, что каждый рендеринг состоит из двух фаз:Reconciliation(фаза координации) иCommit(стадия фиксации).

Я упоминал об этом в нескольких своих предыдущих статьях:«Напишите свой собственный рендерер React: возьмите Remax в качестве примера (написание небольших программ с помощью React)»

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

  • ⚛️ Этап согласования: можно рассматривать как стадию Diff,Этот этап можно прервать, на этом этапе будут найдены все изменения узла, такие как добавление узла, удаление, изменение атрибута и т. д. Эти изменения называются '副作用, (Эффект) «Следующий крючок жизненного цикла будет вызван в стадии координации:

    • constructor
    • componentWillMountзаброшенный
    • componentWillReceivePropsзаброшенный
    • static getDerivedStateFromProps
    • shouldComponentUpdate
    • componentWillUpdateзаброшенный
    • render
  • ⚛️ Стадия фиксации: **побочные эффекты (Effects)**, которые необходимо обработать, рассчитанные на предыдущем этапе, выполняются одновременно.Эта фаза должна выполняться синхронно и не может быть прервана, Эти хуки жизненного цикла выполняются на этапе фиксации:

    • getSnapshotBeforeUpdate()Строго говоря, это вызывается перед входом в фазу коммита.
    • componentDidMount
    • componentDidUpdate
    • componentWillUnmount

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

Примечание: поскольку этап согласования может быть прерван, возобновлен или даже переделан,⚠️ Хуки жизненного цикла фазы согласования React могут вызываться несколько раз!, напримерcomponentWillMountМожет вызываться дважды.

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


Теперь вы должны знать, почему «фаза фиксации» должна выполняться синхронно и не может быть прервана, верно? Потому что нам нужно правильно обрабатывать различные побочные эффекты, включая изменения DOM, и вашиcomponentDidMountАсинхронные запросы, инициированные в , побочные эффекты, определенные в useEffect... Поскольку существуют побочные эффекты, он должен быть гарантированно вызван только один раз по порядку, и будут изменения, которые могут воспринять пользователи, и нет пула допусков.

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



3. Reconcilation

Далее то, что мы знаемReconcilation(Для удобства понимания в этой статье не проводится различие между Diff и Reconcilation, это одно и то же) stage.Идея не сильно отличается от того, что было до рефакторинга Fiber, за исключением того, что здесь не будет выполняться рекурсивное сравнение, и изменения не будут отправлены сразу..

Присмотритесь сначалаFiberСтруктура:

interface Fiber {
  /**
   * ⚛️ 节点的类型信息
   */
  // 标记 Fiber 类型, 例如函数组件、类组件、宿主组件
  tag: WorkTag,
  // 节点元素类型, 是具体的类组件、函数组件、宿主组件(字符串)
  type: any,

  /**
   * ⚛️ 结构信息
   */ 
  return: Fiber | null,
  child: Fiber | null,
  sibling: Fiber | null,
  // 子节点的唯一键, 即我们渲染列表传入的key属性
  key: null | string,

  /**
   * ⚛️ 节点的状态
   */
  // 节点实例(状态):
  //        对于宿主组件,这里保存宿主组件的实例, 例如DOM节点。
  //        对于类组件来说,这里保存类组件的实例
  //        对于函数组件说,这里为空,因为函数组件没有实例
  stateNode: any,
  // 新的、待处理的props
  pendingProps: any,
  // 上一次渲染的props
  memoizedProps: any, // The props used to create the output.
  // 上一次渲染的组件状态
  memoizedState: any,


  /**
   * ⚛️ 副作用
   */
  // 当前节点的副作用类型,例如节点更新、删除、移动
  effectTag: SideEffectTag,
  // 和节点关系一样,React 同样使用链表来将所有有副作用的Fiber连接起来
  nextEffect: Fiber | null,

  /**
   * ⚛️ 替身
   * 指向旧树中的节点
   */
  alternate: Fiber | null,
}

Свойства, содержащиеся в волокне, можно разделить на 5 частей:

  • 🆕 Информация о структуре- Мы видели это выше, Fiber использует форму связанного списка для представления расположения узлов в дереве.

  • Информация о типе узла- Это также легко понять, тег представляет собой классификацию узла, а тип сохраняет значение определенного типа, например div, MyComp.

  • состояние узла- Экземпляр компонента узла, реквизиты, состояние и т. д., которые будут влиять на вывод компонента.

  • 🆕 Побочные эффекты- Это также новшество: «побочные эффекты» (требования к изменению), обнаруженные в процессе согласования, сохраняются в памяти узла.effectTagв (думаю поставить отметку). Так как же собрать все побочные эффекты узла этого рендеринга? Здесь также используется структура связанного списка: в процессе обхода React будет пропускать через себя все узлы с «побочными эффектами».nextEffectсоединить их

  • 🆕 Стенд-ин- React построит новое дерево во время процесса согласования (официально называемое деревом workInProgress,WIP-дерево), которое можно рассматривать как дерево, представляющее текущий ход работы. Так же есть представление отрендеренного интерфейсастарое дерево, React строит дерево WIP, сравнивая его со старым деревом. alter указывает на эквивалентный узел в старом дереве.


Теперь вы можете увеличитьbeginWorkВот как можно сравнить волокна:

function beginWork(fiber: Fiber): Fiber | undefined {
  if (fiber.tag === WorkTag.HostComponent) {
    // 宿主节点diff
    diffHostComponent(fiber)
  } else if (fiber.tag === WorkTag.ClassComponent) {
    // 类组件节点diff
    diffClassComponent(fiber)
  } else if (fiber.tag === WorkTag.FunctionComponent) {
    // 函数组件节点diff
    diffFunctionalComponent(fiber)
  } else {
    // ... 其他类型节点,省略
  }
}

Сравнение хост-узлов:

function diffHostComponent(fiber: Fiber) {
  // 新增节点
  if (fiber.stateNode == null) {
    fiber.stateNode = createHostComponent(fiber)
  } else {
    updateHostComponent(fiber)
  }

  const newChildren = fiber.pendingProps.children;

  // 比对子节点
  diffChildren(fiber, newChildren);
}

Сравнение узлов компонента класса аналогично:

function diffClassComponent(fiber: Fiber) {
  // 创建组件实例
  if (fiber.stateNode == null) {
    fiber.stateNode = createInstance(fiber);
  }

  if (fiber.hasMounted) {
    // 调用更新前生命周期钩子
    applybeforeUpdateHooks(fiber)
  } else {
    // 调用挂载前生命周期钩子
    applybeforeMountHooks(fiber)
  }

  // 渲染新节点
  const newChildren = fiber.stateNode.render();
  // 比对子节点
  diffChildren(fiber, newChildren);

  fiber.memoizedState = fiber.stateNode.state
}

Сравнение подузлов:

function diffChildren(fiber: Fiber, newChildren: React.ReactNode) {
  let oldFiber = fiber.alternate ? fiber.alternate.child : null;
  // 全新节点,直接挂载
  if (oldFiber == null) {
    mountChildFibers(fiber, newChildren)
    return
  }

  let index = 0;
  let newFiber = null;
  // 新子节点
  const elements = extraElements(newChildren)

  // 比对子元素
  while (index < elements.length || oldFiber != null) {
    const prevFiber = newFiber;
    const element = elements[index]
    const sameType = isSameType(element, oldFiber)
    if (sameType) {
      newFiber = cloneFiber(oldFiber, element)
      // 更新关系
      newFiber.alternate = oldFiber
      // 打上Tag
      newFiber.effectTag = UPDATE
      newFiber.return = fiber
    }

    // 新节点
    if (element && !sameType) {
      newFiber = createFiber(element)
      newFiber.effectTag = PLACEMENT
      newFiber.return = fiber
    }

    // 删除旧节点
    if (oldFiber && !sameType) {
      oldFiber.effectTag = DELETION;
      oldFiber.nextEffect = fiber.nextEffect
      fiber.nextEffect = oldFiber
    }

    if (oldFiber) {
      oldFiber = oldFiber.sibling;
    }

    if (index == 0) {
      fiber.child = newFiber;
    } else if (prevFiber && element) {
      prevFiber.sibling = newFiber;
    }

    index++
  }
}

Вышеприведенный код примерно восстанавливает процесс Реконсилиации, но нам его достаточно, чтобы понять основные принципы React.


цитата здесьYoutube: Lin Clark presentation in ReactConf 2017Слайд, чтобы восстановить процесс примирения. Речь Лина Кларка настолько классическая, что почти все статьи, представляющие React Fiber, будут ссылаться на его Слайд. Поленитесь, я также использую:

эта статья«Реактивное волокно»Ссылка Clark Slide объяснена в текстовой версии.


На приведенном выше рисунке показано состояние после завершения согласования, старое дерево находится слева, а дерево незавершенного производства — справа. Узлы, которые необходимо изменить, отмечены «метками». На этапе фиксации React применяет изменения к этим помеченным узлам.



4. Двойная буферизация

WIP 树Построение этой техники похоже на «Графический домен».Двойная буферизация'Технология, механизм рендеринга графики обычно использует технологию двойной буферизации, сначала рисует изображение в буфер, а затем передает его на экран для отображения за один раз, что может предотвратить дрожание экрана и оптимизировать производительность рендеринга.

В React дерево WIP представляет собой буфер, который отправляется в браузер для рендеринга сразу после завершения согласования. Это может уменьшить выделение памяти и сборку мусора.Узлы WIP не совсем новые.Например, поддерево не нужно менять.React клонирует и повторно использует поддерево в старом дереве.

В технологии Dual Coke есть еще одна важная сцена — ненормальный процесс, например, когда узел выдает исключение, вы можете продолжать следовать за узлами старого дерева, чтобы не зависать по всему дереву.

Дэн вBeyond React 16В выступлении была использована очень удачная аналогия — ветки функций Git,Вы можете думать о WIP-дереве как ответвлении ветви функций от старого дерева.Вы добавляете или удаляете функции из новой ветви, и даже неверный шаг не влияет на старую ветвь. Когда ваша ветка будет протестирована и доработана, вы можете слиться со старой веткой и заменить ее.Может быть, отсюда и появился термин «фаза коммита»?:




5. Сбор и представление побочных эффектов

Следующим шагом является последовательное соединение всех узлов, отмеченных Эффектом, которые можно найти вcompleteWorkв, например:

function completeWork(fiber) {
  const parent = fiber.return

  // 到达顶端
  if (parent == null || fiber === topWork) {
    pendingCommit = fiber
    return
  }

  if (fiber.effectTag != null) {
    if (parent.nextEffect) {
      parent.nextEffect.nextEffect = fiber
    } else {
      parent.nextEffect = fiber
    }
  } else if (fiber.nextEffect) {
    parent.nextEffect = fiber.nextEffect
  }
}

Наконец, зафиксируйте все побочные эффекты:

function commitAllWork(fiber) {
  let next = fiber
  while(next) {
    if (fiber.effectTag) {
      // 提交,偷一下懒,这里就不展开了
      commitWork(fiber)
    }
    next = fiber.nextEffect
  }

  // 清理现场
  pendingCommit = nextUnitOfWork = topWork = null
}


⚠️ Нераскрытый раздел 🚧 -- прерывание и возобновление

Вышеизложенное представляет собой простой механизм прерывания и восстановления: мы встаем с того места, где упали, и продолжаем обработку с того узла, на котором нас прервали. То есть пока:⚠️Задачи обновления по-прежнему выполняются последовательно, мы просто фрагментируем весь процесс, те задачи обновления, которые должны быть приоритетными, все равно будут заблокированы.. Лично я считаю, что это самая сложная часть React Fiber.

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

Однако, если задачи выполняются вне последовательности, это может привести к несогласованному состоянию до и после. Например, задача с низким приоритетом будетaустановлено значение 0, и задачи с высоким приоритетом будутaПри увеличении на 1 порядок выполнения двух задач повлияет на окончательный результат рендеринга. следовательноЧтобы разрешить высокоприоритетным задачам переходить из очереди, сначала обеспечьте синхронизацию обновлений состояния..


Решение:Все задачи обновления вставляются в очередь по порядку, состояние должно рассчитываться в порядке вставки, но задачи могут выполняться в порядке приоритета, например:



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


Последняя красная задача с высоким приоритетомCЗначение состояния при времени выполненияa=5,b=3В рекавери, когда управление будет выполнено в соответствии с первым приоритетомC, переднийA,Bпропустить сейчас



Пропущенные выше задачи не будут удалены, они все равно будут выполняться после выполнения задач с высоким приоритетом. Поскольку диапазон деревьев узлов, затронутых разными задачами обновления, может быть разным, напримерa,bможет повлиятьFooСоставное дерево, иcповлияетBarдерево компонентов. Таким образом, чтобы обеспечитьПросмотр возможной согласованности, выполняются все задачи обновления.


первыйCвыполняется первым, он обновляетFooкомпоненты

Затем выполнитеAзадача, она обновленаFooа такжеBarкомпоненты, из-заCв конечном состоянииa=5, b=3обновленFooКомпоненты, здесь вы можете оптимизировать производительность и повторно использовать результаты обновления C напрямую, не запуская повторный рендеринг. следовательноAпросто обновиBarкомпоненты.

Затем выполнитеB, таким же образом Foo можно повторно использовать для обновления результата.


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



Лимбо Микрошаг

Также из Slider Линка Кларка

Многое было сказано ранее, от планирования процессов операционной системы до принципов работы браузера, совместного планирования и, наконец, базовой трансформации React.

Реакция включенаConcurrent ModeПосле этого я не буду копать большие ямы, но копать маленькие ямы один за другим, копать некоторое время и отдохнуть и отдавать приоритет на срочные задачи.


источник:Flarnie Marchan - Ready for Concurrent Mode?


включиConcurrent ModeПосле этого мы можем получить следующие преимущества (см.Concurrent Rendering in React):

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

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

Чтобы вместе создать лучший мир, мы должны быть строги к себе, и оптимизации, которые мы должны сделать, все еще должны быть сделаны: чистые компоненты, виртуальные таблицы, упрощенные компоненты, кэширование...

Юйси в этом годуVue ConfМеня поразил один момент:Если мы сможем делать обновления достаточно быстро, теоретически нет необходимости во временном сегментировании..

Разбивка по времени не снижает общую нагрузку, то, что нужно сделать, еще предстоит сделать, поэтому React также рассматривает возможность использования простоя ЦП или периодов простоя ввода-вывода для выполнения некоторого предварительного рендеринга. Итак, как сказал Ю Юйси: React Fiber, по сути, должен решить проблему низкой эффективности обновления React,Не ждите, что Fiber качественно улучшит ваши существующие приложения..



Стоя на плечах гигантов


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

Внедрение мини-волокна:

Текущая кодовая база React слишком сложна, и она постоянно меняется и ниспровергает себя.HaxсуществуетПочему эти React-подобные библиотеки в сообществе еще не решили реализовать архитектуру Fiber? 》Просто в шутку сказал: волокно чуть менее рентабельно... На данном этапе слишком много конкурирующих продуктов, поэтому Facebook будет строить волокно как ров...

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


Отличная статья и речь

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


Саморекомендуемые статьи, связанные с React

Просмотрите связанные статьи, написанные о React в этом году.

Предварительный просмотр параллельного режима (рекомендуется):


Прошлые статьи:


В этой статье рассказывается о том, как React оптимизирует процессор, амбиции React далеко не здесь, и оптимизация в направлении ввода-вывода также на практике, например Suspend... Еще многое предстоит доделать, увидимся в следующем статья!


Анкета, что вы думаете о стиле этой статьи?

  • А. Это слишком многословно.
  • B. Мне нравится объяснять это простым способом
  • C. Содержание недостаточно глубокое
  • D. Статья слишком длинная и ее можно разделить

Множественный выбор, комментируйте ниже, 👍 Ставьте лайк и переходите


Изменено более серьезное псевдоним:sx(Глупая вилка) -> Бесплодная гора ⛰