Ранним утром 11 августа по пекинскому времени,React团队
опубликованоReact17
ПервыйRC版本
. Самая большая особенность этой версии — «нет новых функций».
Итак, изv16
прибытьv17
более годаReact团队
Что именно вы делаете?
издалекаv15
прибытьv16
,React团队
Потребовалось два года, чтобы поместить исходный код в архитектуруStack Reconciler
преобразован вFiber Reconciler
, все не должно быть так просто.
На самом деле, это изменение версии имеет «новые функции» — замена внутренне используемого启发式更新算法
.
Просто эта особенность незаметна для разработчиков.
В этой статье будет описано следующее:
-
Происхождение: почему оно пришло
启发式更新算法
? -
статус-кво:
React16
из启发式更新算法
и его недостатки -
будущее:
React17
из启发式更新算法
Почему появляются эвристические алгоритмы обновления?
框架
Операционная производительность框架设计者
На что обратить внимание при разработке фреймворка.
Vue
использовать模版语法
, который может оптимизировать определенные шаблоны во время компиляции.
а такжеReact
чистыйJS
Письмо настолько гибкое, что он编译时优化
Врожденные недостатки.
так,React
Оптимизация в основном в运行时
.
Болевые точки React15
существует运行时优化
аспект,React
Пытался.
Например,React15
ДостигнутоbatchedUpdates
(массовое обновление).
То есть несколько раз в контексте одной и той же функции обратного вызова события.setState
сработает только один раз更新
.
Однако, если один更新
Это занимает очень много времени, и страница все равно будет зависать (это очень часто встречается в больших приложениях с длительным временем обслуживания).
Это потому чтоReact15
Процесс обновления同步
Выполняется, после запуска обновления его нельзя прервать, пока страница не будет отрисована.
чтобы решить同步更新
Проблема в том, что ветка занята на долгое время, вызывает зависание страницы, а также для изучения运行时优化
больше возможностей,React
Начал рефакторинг и продолжается по сей день.
Цель рефакторинга состоит в том, чтобы достичьConcurrent Mode
(параллельный режим).
Concurrent Mode
Concurrent Mode
Цель состоит в том, чтобыРеализовать прерываемый/возобновляемый механизм обновления.
Он состоит из двух частей:
-
задавать
协程架构
-
на основе
协程架构
из启发式更新算法
в,协程架构
то естьReact16
реализовано вFiber Reconciler
.
мы можем поставитьFiber Reconciler
понимается какReact
самореализованныйGenerator
.
Fiber Reconciler
Подробное введение от концепции до исходного кода см.здесь
协程架构
Сделать更新
Может быть прерван, когда это необходимо, чтобы у браузера было время завершить样式布局
а также样式绘制
, чтобы уменьшить возникновение зависаний (пропущенных кадров).
Когда браузер входит в следующий раз事件循环
,协程架构
Могу恢复中断
или отказаться от предыдущего更新
, чтобы снова начать новый процесс обновления.
启发式更新算法
состоит в том, чтобы контролировать协程架构
Как работает алгоритм.
Эвристический алгоритм обновления для React16
启发式更新算法
из启发式
Что ты имеешь в виду?
启发式
означает провал显式的指派
, но через优先级
Расписание обновлений.
в优先级
получено из人机交互的研究成果
.
Например:
人机交互的研究成果
показывать:
-
Когда пользователь вводит содержимое в поле ввода, предполагается, что вводимое содержимое может реагировать на поле ввода в режиме реального времени.
-
Когда данные запрашиваются асинхронно, они приемлемы для пользователя, даже если он некоторое время ждет перед отображением содержимого.
Исходя из этого, вReact16
середина
输入框输入内容触发的`更新`优先级 > 请求数据返回后触发`更新`优先级
Реализация алгоритма
существуетReact16、17
, выполнить внутри компонентаthis.setState
После этого он будет соответствовать компонентуfiber节点
создать структуру данных связанного спискаupdate
.
в,update.expirationTimes
для подобных时间戳
поле, указывающее优先级
.
expirationTimes
буквально понимается как过期时间
.
Чем ближе значение к текущему времени, темupdate
优先级
выше.
когдаupdate.expirationTimes
превышает текущее время, это означаетupdate
Истекший,优先级
становится высшим (т.同步
).
деревоfiber树
несколькихfiber节点
может быть несколькоupdate
.
каждый разFiber Reconciler
расписание更新
, будет во всехfiber节点
всеupdate.expirationTimes
Выбери одинexpirationTimes
(Вообще выбираем самое большое), так как на этот раз更新
из优先级
.
и из根fiber节点
начать строить новыйfiber树
.
В процессе сборки, еслиfiber节点
Включатьupdate
,а также
update.expirationTimes >= expirationTimes
затемupdate
соответствующийstate
Изменения будут отражены в этом更新
середина.
Это можно понять как: каждый раз更新
, выберет优先级
(expirationTimes), последняя страница будет отображаться как优先级
вести перепискуupdate
снимок.
Например, у нас есть, как показаноfiber树
, еще нет更新
производит, так что нет构建中
изfiber树
.
когда вC
Создавать低优先级update
, планирование更新
,этот раз更新
Выбранный приоритет低优先级
.
начать строить новыйfiber树
(правая сторона рисунка).
В это время мыD
Создавать高优先级update
.
Это прервет текущий процесс低优先级更新
, начните с高优先级
Создатьfiber树
.
из-за предыдущего更新
Прервано, в настоящее время нет операции рендеринга视图中
(левое изображение) Пока ничего не изменилось.
этот раз更新
Выбранный приоритет高优先级
,C
изupdate
(низкий приоритет) будут пропущены.
новый после обновленияfiber树
будет предоставлено视图
середина.
из-заC
пропущено, поэтому не будет视图
(левое изображение).
Далее мыE
триггер один раз高优先级update
.
C
Хотя он содержит低优先级update
, но со временем егоexpirationTimes
истек, стал高优先级
.
Так что это обновление будет иметьC
E
дваfiber节点
Сделать разницу.
После окончательного обновления вид выглядит следующим образом:
Об обновлении
优先级
Справочник по подробному объяснениюздесь
Недостатки алгоритма
Если только рассмотреть прерывание/продолжение, как этоCPU操作
,кexpirationTimes
размер как мера优先级
Базовая модель работает нормально.
ноexpirationTimes模型
не может удовлетворитьIO操作
(Саспенс).
В этой модели高优先级IO任务
(Приостановка) сломается低优先级CPU任务
.
Помните, каждый раз更新
, все с определенной优先级
как целое дерево优先级
обновить стандарт, а не только компонент, даже если更新
Источник (обновление) действительно генерируется компонентом.
expirationTimes模型
только для того, чтобы отличить>=expirationTimes
Эта ситуация.
расширятьConcurrent Mode
границы возможностей, более детальное启发式优先级更新算法
.
Алгоритм эвристического обновления React17
Самая идеальная модель: вы можете указать любое количество优先级
,更新
будут использовать эти优先级
вести перепискуupdate
Создание снимков страницы.
Однако при существующей архитектуре есть узкие места в реализации этого решения.
под компромиссом,React17
Решение: укажите непрерывный优先级区间
,каждый раз更新
будет区间
включены优先级
Создайте снимок соответствующей страницы.
это优先级区间
модель называетсяlanes
(модель полосы).
Конкретный подход таков: используйте 31-битный двоичный файл для представления 31 возможности.
-
каждый из них
bit
называетсяlane
(переулок), представляющий优先级
-
несколько
lane
Состоит из двоичных чисел, называетсяlanes
, представляющий партию优先级
Как видно из исходного кода, от синей линии до конца вниз каждыйbit
соответствует одномуlane
илиlanes
.
когдаupdate
производится, будет основано наReact16
такой же启发式
способ получить следующее优先级
Типа:
export const SyncLanePriority: LanePriority = 17;
export const SyncBatchedLanePriority: LanePriority = 16;
export const InputDiscreteLanePriority: LanePriority = 14;
export const InputContinuousLanePriority: LanePriority = 12;
export const DefaultLanePriority: LanePriority = 10;
export const TransitionShortLanePriority: LanePriority = 8;
export const TransitionLongLanePriority: LanePriority = 6;
Чем выше значение, тем выше приоритет.
Например:
-
点击事件回调
средний триггерthis.setState
произведеноupdate
получитеInputDiscreteLanePriority
. -
Синхронный
update
получитеSyncLanePriority
.
Следующий,update
Будуpriority
Найдите незанятые для подсказокlane
.
если текущийfiber树
уже существует更新
а также更新
изlanes
содержитlane
,ноupdate
нужно найти другиеlane
.
Например,InputDiscreteLanePriority
соответствующийlanes
дляInputDiscreteLanes
.
// 第4、5位为1
const InputDiscreteLanes: Lanes = 0b0000000000000000000000000011000;
Долженlanes
В том числе 4-й и 5-й 2bit位
.
если среди
// 第五位为1
0b0000000000000000000000000010000
пятыйlane
занято, т.update
Можно попытаться обладать последним, т.е.
// 第四位为1
0b0000000000000000000000000001000
еслиInputDiscreteLanes
дваlane
заняты, т.update
приоритет упадет доInputContinuousLanePriority
и продолжаю искать запчастиlane
.
Процесс такой: на каждом этаже торгового центра (разного приоритета) есть открытая парковка (полосы), а на парковке несколько парковочных мест (полос).
Сначала мы подъезжаем к верхнему этажу, чтобы найти место для парковки (полосу), а если места для парковки нет, продолжаем искать следующий этаж.
пока не будет найдено свободное парковочное место.
из-заlanes
может содержать несколькоlane
, легко отличитьIO操作
(Приостановка) сCPU操作
.
Быть построеннымfiber树
Введите сборкуSuspense子树
, будуSuspense
изlane
Вставьте это время更新
Выбраноlanes
середина.
когда сборка уходитSuspense子树
, будуSuspense lane
С этого времени更新
изlanes
удалено в.
Суммировать
React16
изexpirationTimes模型
только для того, чтобы отличить>=expirationTimes
Определяет, обновляется ли узел.
React17
изlanes模型
можно выбрать один更新区间
, и динамически区间
увеличить или уменьшить优先级
, который может обрабатывать более мелкие обновления.
Наконец, я рекомендую серию книг по React с открытым исходным кодом —Демистификация технологии React