Новая функция React17: эвристический алгоритм обновления

React.js
Новая функция React17: эвристический алгоритм обновления

Ранним утром 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