Зачем нужен приоритет
Конечной целью механизма приоритета является достижениеЗадачи с высоким приоритетом выполняются первыми, а задачи с низким приоритетом выполняются позже..
Суть этого назначения в том, что при выполнении низкоприоритетной задачи, если приходит более высокоприоритетная задача, выполнение низкоприоритетной задачи может быть прервано.
Среда выполнения React в синхронном режиме
Мы знаем, что в синхронном режиме изsetState
От обхода виртуального DOM до реального обновления DOM весь процесс выполняется синхронно и не может быть прерван, поэтому может возникнуть проблема — обновление, вызванное пользовательскими событиями, заблокировано.
Что такое заблокированное обновление, вызванное пользовательским событием? еслиReact
Выполняется задача обновления, и пользователь инициирует событие взаимодействия, которое выполняется в обратном вызове события.setState
,существуетРежим синхронизацииДалее для этой задачи обновления требуется等待
Он будет выполнен только после завершения текущей обновляемой задачи. Если текущийReact
Текущая задача обновления занимает много времени, и задача обновления, запущенная пользовательским событием, не может быть выполнена вовремя, что приводит к блокировке следующей задачи обновления, что приводит к зависанию.
В настоящее время мы надеемся, что сможем своевременно реагировать на события, инициированные пользователем, и расставлять приоритеты при выполнении задач обновления, инициируемых пользовательскими событиями, что мы называемАсинхронный режим
Мы можем сравнить,Режим синхронизацииСяхэАсинхронный режим(优先级机制
), чтобы обновить разницу в выполнении задачи
import React from "react";
import "./styles.css";
export default class extends React.Component {
constructor() {
super();
this.state = {
list: new Array(10000).fill(1),
};
this.domRef = null;
}
componentDidMount() {
setTimeout(() => {
console.log("setTimeout 准备更新", performance.now());
this.setState(
{
list: new Array(10000).fill(Math.random() * 10000),
updateLanes: 16
},
() => {
console.log("setTimeout 更新完毕", performance.now());
}
);
}, 100);
setTimeout(() => {
this.domRef.click();
}, 150);
}
render() {
const { list } = this.state;
return (
<div
ref={(v) => (this.domRef = v)}
className="App"
onClick={() => {
console.log("click 准备更新", performance.now());
this.setState(
{ list: new Array(10000).fill(2), updateLanes: 1 },
() => {
console.log("click 更新完毕", performance.now());
}
);
}}
>
{list.map((i, index) => (
<h1 key={i + +index}>Hello {i}</h1>
))}
</div>
);
}
}
Приведенный выше код находится вРежим синхронизацииПечать ниже
можно увидетьclick事件
Запущено обновление, нужно подождатьsetTimeout
Инициированные обновления будут выполняться
Приведенный выше код находится вАсинхронный режимПечать ниже
можно увидетьclick事件
Триггерных обновлений будет меньше, чемsetTimeout
Триггерные обновления выполняются более предпочтительно, чтобы своевременно реагировать на пользовательские события и прерыватьsetTimeout
обновить задачу (低优先级任务
) исполнение.
Я в приведенном выше кодеcodesandboxНаписал демо и запустил их отдельноreact15
а такжеreact18
Под двумя версиями, если интересно, можно поковыряться напрямую.
Как использовать механизм приоритета для оптимизации времени выполнения реакции
Чтобы устранить дефекты рендеринга в синхронном режиме, мы надеемся, что сможемreact
Сделайте следующие оптимизации
- Приоритизируйте обновления, вызванные различными сценариями, чтобы мы могли решить, каким задачам отдать приоритет.
- Если приходит задача с более высоким приоритетом, нам нужно прервать текущую задачу и выполнить эту задачу с высоким приоритетом
- Убедитесь, что задачи с низким приоритетом не прерываются все время и могут быть обновлены до задачи с наивысшим приоритетом через определенный период времени.
Определение приоритетов планирования в различных сценариях
Видимыйreact
У мелких партнеров исходного кода может возникнуть сомнение, почему в исходном коде так много слов, связанных с приоритетом? ? Как их отличить?
по фактуreact
Существуют в основном два типа приоритетов,scheduler
приоритет иlane
приоритет,lane
Ниже приоритет выводится сноваevent
приоритет
- Приоритет полосы: он в основном используется для проверки приоритета текущей задачи и запланированной задачи перед планированием задачи, чтобы определить, нужно ли прервать текущую текущую задачу.
- Приоритет события: это, по сути, также приоритет полосы, приоритет полосы является общим, приоритет события больше сочетается с собственными событиями браузера, а приоритет полосы классифицируется и отображается.
- приоритет планировщика: в основном используется для расчета времени истечения задачи при квантовании времени
приоритет полосы движения
Понятие дорожки можно использовать для понимания приоритета дорожки. Существует 31 приоритет дорожки. Мы можем использовать 31-битное двоичное значение для его представления. Каждый бит значения представляет дорожку, соответствующую приоритету дорожки.Чем выше позиция дорожки, тем выше приоритет
приоритет | десятичное значение | двоичное значение | отслеживать местоположение |
---|---|---|---|
NoLane | 0 | 0000000000000000000000000000000 | 0 |
SyncLane | 1 | 0000000000000000000000000000001 | 0 |
InputContinuousHydrationLane | 2 | 0000000000000000000000000000010 | 1 |
InputContinuousLane | 4 | 0000000000000000000000000000100 | 2 |
DefaultHydrationLane | 8 | 0000000000000000000000000001000 | 3 |
DefaultLane | 16 | 0000000000000000000000000010000 | 4 |
TransitionHydrationLane | 32 | 0000000000000000000000000100000 | 5 |
TransitionLane1 | 64 | 0000000000000000000000001000000 | 6 |
TransitionLane2 | 128 | 0000000000000000000000010000000 | 7 |
TransitionLane3 | 256 | 0000000000000000000000100000000 | 8 |
TransitionLane4 | 512 | 0000000000000000000001000000000 | 9 |
TransitionLane5 | 1024 | 0000000000000000000010000000000 | 10 |
TransitionLane | 2048 | 0000000000000000000100000000000 | 11 |
TransitionLane7 | 4096 | 0000000000000000001000000000000 | 12 |
TransitionLane8 | 8192 | 0000000000000000010000000000000 | 13 |
TransitionLane9 | 16384 | 0000000000000000100000000000000 | 14 |
TransitionLane10 | 32768 | 0000000000000001000000000000000 | 15 |
TransitionLane11 | 65536 | 0000000000000010000000000000000 | 16 |
TransitionLane12 | 131072 | 0000000000000100000000000000000 | 17 |
TransitionLane13 | 262144 | 0000000000001000000000000000000 | 18 |
TransitionLane14 | 524288 | 0000000000010000000000000000000 | 19 |
TransitionLane15 | 1048576 | 0000000000100000000000000000000 | 20 |
TransitionLane16 | 2097152 | 0000000001000000000000000000000 | 21 |
RetryLane1 | 4194304 | 0000000010000000000000000000000 | 22 |
RetryLane2 | 8388608 | 0000000100000000000000000000000 | 23 |
RetryLane3 | 16777216 | 0000001000000000000000000000000 | 24 |
RetryLane4 | 33554432 | 0000010000000000000000000000000 | 25 |
RetryLane5 | 67108864 | 0000100000000000000000000000000 | 26 |
SelectiveHydrationLane | 134217728 | 0001000000000000000000000000000 | 27 |
IdleHydrationLane | 268435456 | 0010000000000000000000000000000 | 28 |
IdleLane | 536870912 | 0100000000000000000000000000000 | 29 |
OffscreenLane | 1073741824 | 1000000000000000000000000000000 | 30 |
приоритет события
EventPriority | Lane | Численная величина | |
---|---|---|---|
DiscreteEventPriority | дискретные события. Щелчок, нажатие клавиши, фокусировка и т. Д., Запуск событий не является непрерывным, и можно добиться быстрого реагирования. | SyncLane | 1 |
ContinuousEventPriority | последовательные события. Перетаскивание, прокрутка, наведение мыши и т. д., события запускаются постоянно, быстрый отклик может блокировать рендеринг, а приоритет ниже, чем у дискретных событий. | InputContinuousLane | 4 |
DefaultEventPriority | Приоритет события по умолчанию | DefaultLane | 16 |
IdleEventPriority | приоритет бездействия | IdleLane | 536870912 |
приоритет планировщика
SchedulerPriority | EventPriority | Больше >17.0.2 | Менее >17.0.2 |
---|---|---|---|
ImmediatePriority | DiscreteEventPriority | 1 | 99 |
UserblockingPriority | Userblocking | 2 | 98 |
NormalPriority | DefaultEventPriority | 3 | 97 |
LowPriority | DefaultEventPriority | 4 | 96 |
IdlePriority | IdleEventPriority | 5 | 95 |
NoPriority | 0 | 90 |
переход между приоритетами
-
приоритет полосы перед приоритетом события (см.
lanesToEventPriority
функция)- Правило преобразования: возвращает соответствующий приоритет события в виде интервала согласно входящей дорожке. Например, если входящий приоритет не превышает дискретного приоритета, будет возвращен дискретный приоритет и так далее.
-
приоритет события перед приоритетом планировщика (см.
ensureRootIsScheduled
функция)- Правила преобразования: вы можете обратиться к таблице приоритетов планировщика выше.
-
приоритет события для приоритета полосы движения (см.
getEventPriority
функция)- Правила преобразования: Для недискретных и непрерывных событий они будут преобразованы в соответствии с определенными правилами.Для конкретных уроков, пожалуйста, обратитесь к таблице приоритетов событий выше.
Как устроен механизм приоритета
Когда речь идет о приоритетном механизме, мы скоро сможем думать о том, что это приоритетная очередь, его самая выдающаяся функциясначала наивысший приоритет,react
Механизм приоритета подобен очереди приоритетов, но он используетгоночная трассаконцепция, подходитпобитовое ИФункция очереди обогащена. По сравнению с очередью приоритета, скорость чтения и записи быстрее и легче понять.
Идеи дизайна
- Объединить треки: поддерживать очередь, в которой можно хранить занятые треки
- Освободить дорожку: освободить соответствующую занятую дорожку в соответствии с приоритетом.
- Найти дорожку с наивысшим приоритетом: получить дорожку с наивысшим приоритетом в очереди.
- Быстро найти индекс трека: получить позицию трека в очереди в соответствии с приоритетом
- Определить, занята ли дорожка: по входящему приоритету определить, занята ли дорожка, на которой находится приоритет
объединить трек
-
Сцены
- Например, приоритет текущей запланированной задачи — DefaultLane, пользователь щелкает, чтобы запустить обновление, генерируется задача с высоким приоритетом SyncLane, и необходимо сохранить дорожку, занимаемую этой задачей.
-
Процесс работы
- Метод операции: побитовая операция ИЛИ -
a | b
- Результат операции: DefaultLane и SyncLane занимают 1-ю и 5-ю дорожки соответственно.
- Метод операции: побитовая операция ИЛИ -
DefaultLane优先级为16,SyncLane优先级为1
16 | 1 = 17
17的二进制值为10001
16的二进制值为10000,1的二进制值为00001
бесплатный трек
-
Сцены
- После выполнения задачи SyncLane занятую дорожку необходимо освободить
-
Процесс работы
- Режим работы: бит и + бит не -
a & ~b
- Результат операции: дорожка SyncLane освобождается, остается только дорожка DefaultLane.
- Режим работы: бит и + бит не -
17 & ~1 = 16
17的二进制值为10001
为什么用位非?
~1 = -2
2 的二进制是00010,-2的话符号位取反变为10010
10001和10010进行位与运算得到10000,也就是十进制的16
Найти дорожку с наивысшим приоритетом
-
Сцены
- В настоящее время дорожку занимают две приоритетные задачи, DefaultLane и SyncLane.После входа в метод sureRootIsScheduled мне нужно сначала запланировать задачу с наивысшим приоритетом, поэтому мне нужно найти дорожку с наивысшим приоритетом.
-
Процесс работы
- Режим работы: бит и знак + отрицание бита -
a & -b
- Результат операции: Найдена задача SyncLane с наивысшим приоритетом. Задача SyncLane является задачей синхронизации. Планировщик запланирует текущий корневой узел приложения с приоритетом синхронизации.
- Режим работы: бит и знак + отрицание бита -
17 & -17 = 1
17的二进制值为10001
-17的二进制值为00001
10001和00001进行位与运算得到1,也就是SyncLane
Быстро найти индекс трека
-
Сцены
- Пробуждение голодной задачи: перед началом планирования нам необходимо оценить все дорожки в очереди, чтобы определить, истек ли срок действия задачи дорожки.Если срок ее действия истек, просроченная задача будет выполнена первой. Для этого необходимо поддерживать массив длиной 31. Нижний индекс каждого элемента массива соответствует 31 приоритетной дорожке один к одному.Срок действия задачиПри оценке мы надеемся быстро найти позицию, соответствующую массиву по приоритету.
-
Процесс работы
- Метод работы: Math.clz32
- Результат операции: если позиция индекса DefaultLane равна 4, то eventTimes и expireTimes на корневом узле приложения могут быть освобождены, а значение его местоположения назначено на -1, а затем соответствующая задача с истекшим сроком действия может быть освобождена. быть казненным.
// 找出 DefaultLane 赛道索引
31 - Math.clz32(16) = 4
16的二进制值为10000
索引4对应的就是第五个赛道
-
Для чего используется Math.clz32?
- Получает количество начальных нулей в двоичном значении, соответствующем десятичному числу.
- Так что вычтите это из 31
Math.clz32
Значение , вы можете получить индекс трека
Определить, занята ли дорожка
Ссылаться наcodesandboxВышеприведенный код,в асинхронном режимеБудут приоритетные задачи, прерывающие очередь, в этом случаеstate
Метод расчета будет следующимв режиме синхронизациинемного отличается.
-
Сцены
- Мы не обновляем сразу после установки состояния
state
, но будет генерировать на основе содержимого setStateUpdate
Object, этот объект содержит такие свойства, как содержимое обновления и приоритет обновления. - возобновить
state
Это действие вprocessUpdateQueue
В функции функция будет судитьUpdate
Занята ли дорожка, на которой находится приоритет объекта, чтобы решить, считать ли это в этом раунде задачUpdate
объектstate
- Если занято, представитель
Update
Приоритет объекта равен выполняемой в данный момент задаче и может быть определен согласноUpdate
объектные вычисленияstate
и обновить до узла FibermemoizedState
атрибут - Если он не занят, это означает, что приоритет выполняемой в данный момент задачи выше, чем этот
Update
Объект имеет высокий приоритет, а соответствующий низкий приоритетUpdate
Состояние объекта временно не будет рассчитываться, и он будет рассчитан при перезапуске следующего раунда низкоприоритетных задач.
- Если занято, представитель
- Мы не обновляем сразу после установки состояния
-
Процесс работы
- Метод работы: бит и
(renderLanes & updateLanes) == updateLanes
- Результат операции: 0 означает, что текущий приоритет планирования выше, чем приоритет объекта Update.
- Метод работы: бит и
运算公式
(1 & 16) == 16
1的二进制值为00001
16的二进制值为10000
00001和10000进行位与运算得到0
Как внедрить механизмы приоритетов в среду выполнения React
Создать задачу обновления
Процесс генерации задач на самом деле очень прост, а вход находится в нашем обычномsetState
функция, первая
setState
То, что выполняется внутри функции,enqueueUpdate
функция, в то время какenqueueUpdate
Работа функции в основном делится на 4 шага:
- Получить приоритет этого обновления.
- Создайте
Update
объект - Свяжите этот приоритет обновления с текущим узлом Fiber, родительским узлом и корневым узлом приложения.
- положить начало
ensureRootIsScheduled
расписание.
Шаг первый: получите этот приоритет обновления
Задача первого шага — позвонитьrequestUpdateLane
Функция получает приоритет задачи обновления
- Если ток не
concurrent
модель- В настоящее время не находится в стадии рендеринга. вернуть синхронную полосу
- Сейчас на этапе рендеринга. Вернуть наивысший приоритет в workInProgressRootRenderLanes (здесь используется вышеуказанный механизм расчета приоритета,Найти дорожку с наивысшим приоритетом)
- если в настоящее время
concurrent
модель- Если вам нужно выполнить отложенные задачи, такие как
Suspend
,useTransition
,useDefferedValue
и другие характеристики. существуетtransition
Введите приоритет, чтобы найти бесплатные треки.transition
Есть 16 типов трасс, от 1 до 16 статьи, при заезде на 16 трассу в следующий разtransition
Типовые миссии возвращаются к дорожке 1 и так далее. - воплощать в жизнь
getCurrentUpdatePriority
функция. Получить текущий приоритет обновления. если неNoLane
просто вернись - воплощать в жизнь
getCurrentEventPriority
функция. Возвращает текущий приоритет события. Если событие не происходит, вернитеDefaultEventPriority
- Если вам нужно выполнить отложенные задачи, такие как
В основном,requestUpdateLane
Порядок приоритетного выбора и оценки функций следующий:
SyncLane >> TransitionLane >> UpdateLane >> EventLane
Подсчитано, что многие мелкие партнеры будут очень смущены вопросом, почему так много функций для получения приоритета, здесь я разобрался с обязанностями других функций.
Шаг 2: Создайте объект обновления
Кода тут немного, по сути, нужно инкапсулировать параметры setState в объект и оставить это на этапе рендеринга.
function createUpdate(eventTime, lane) {
var update = {
eventTime: eventTime,
lane: lane,
tag: UpdateState,
payload: null,
callback: null,
next: null
};
return update;
}
Шаг 3: Связать приоритет
Здесь сначала объясните два понятия, одно из которыхHostRoot
,одинFiberRootNode
-
HostRoot
:то естьReactDOM.render
Первый параметр корневого узла дерева компонентов.HostRoot
Их может быть больше одного, потому чтоReactDOM.render
Можно вызывать несколько раз -
FiberRootNode
: корневой узел приложения React, каждая страница имеет только один корневой узел приложения React. Доступна сHostRoot
узлаstateNode
доступ к собственности
Здесь ассоциированный приоритет в основном выполняет две функции
-
markUpdateLaneFromFiberToRoot
. Эта функция в основном делает две вещи- Объедините приоритет со свойством lanes текущего узла Fiber.
- Включите приоритет в свойство childLanes родителя (сообщает родителю, сколько дорожек должен запустить его ребенок)
HostRoot
, то есть,ReactDOM.render
Корневой узел , то есть родительского узла нет, поэтому второе не делается. -
markRootUpdated
. Эта функция также в основном делает две вещи- Объедините приоритет задач, которые должны быть запланированы, с корневым узлом текущего реагирующего приложения.
- Рассчитать время начала (eventTime), занимаемое текущей дорожкой приоритета задачи
Отсюда видно, чтоreact
Механизм приоритета не работает независимо в каждом узле компонента, а опирается на глобальныйreact
Примените корневой узел для управления планированием задач следующих множественных деревьев компонентов.
БудуприоритетКакая польза от связи с этими узлами Fiber?
Давайте поговорим о нихразница
- дорожки: существуют только на корневом узле нереагирующих приложений, запишите приоритет дорожки текущего узла волокна
- childLanes: существует только на корневом узле нереагирующих приложений и записывает приоритет полосы всех дочерних волоконных узлов под текущим волоконным узлом.
- PendendingLanes: существует только на корневом узле приложения React, и записывает все
HostRoot
приоритет полосы движения
специфическийСценарии применения
- Отпустите трек. В упомянутом выше механизме расчета приоритета упоминается, что дорожка будет освобождена после выполнения задачи, в частности, занятый приоритет будет освобожден после завершения фазы фиксации, т. е.
markRootFinished
функция. - Определите, занята ли дорожка. на этапе рендеринга
beginWork
В процессе будет много сужденийchildLanes
Решение о том, занято ли оно
Шаг 4: Начните планирование
Самый важный шаг в планированииensureRootIsScheduled
Вызов функции, логика функции состоит из следующих двух частей:Задачи с высоким приоритетом прерывают задачи с низким приоритетома такжепроблема голодной миссии
Задачи с высоким приоритетом прерывают задачи с низким приоритетом
Эту часть процесса можно разделить на три части
- cancelCallback
- pop(taskQueue)
- Перезапуск задачи с низким приоритетом
cancelCallback
var existingCallbackNode = root.callbackNode;
var existingCallbackPriority = root.callbackPriority;
var newCallbackPriority = getHighestPriorityLane(nextLanes);
if (existingCallbackPriority === newCallbackPriority) {
...
return;
}
if (existingCallbackNode != null) {
cancelCallback(existingCallbackNode);
}
newCallbackNode = scheduleCallback(
schedulerPriorityLevel,
performConcurrentWorkOnRoot.bind(null, root)
);
root.callbackPriority = newCallbackPriority;
root.callbackNode = newCallbackNode;
вышеensureRootIsScheduled
Некоторые фрагменты кода функции, сначала объясните переменные
-
existingCallbackNode
: задача выполняется на текущем этапе рендеринга. -
existingCallbackPriority
: приоритет текущих задач на текущем этапе рендеринга. -
newCallbackPriority
: этот приоритет планирования
будем судить здесьexistingCallbackPriority
а такжеnewCallbackPriority
Равны ли два приоритета,если равны, это обновление объединяется с текущей задачей.если не равно, что означает, что приоритет этой задачи обновления выше и должен прервать текущую задачу
Как прервать миссию?
- ключевая функция
cancelCallback(existingCallbackNode)
,cancelCallback
функция состоит в том, чтобыroot.callbackNode
присвоить значение null -
performConcurrentWorkOnRoot
Функция будет сначалаroot.callbackNode
Кэшируйте его, и он будет оценен в конце функцииroot.callbackNode
Это то же самое, что значение, которое было изначально кэшировано, если нет, значитroot.callbackNode
Ей присваивается значение null, и в дело вступает задача с более высоким приоритетом. - В настоящее время
performConcurrentWorkOnRoot
возвращаемое значение равно нулю
НижеperformConcurrentWorkOnRoot
сегмент кода
...
var originalCallbackNode = root.callbackNode;
...
// 函数末尾
if (root.callbackNode === originalCallbackNode) {
return performConcurrentWorkOnRoot.bind(null, root);
}
return null;
Из вышеперечисленногоensureRootIsScheduled
Фрагмент кода может знать,performConcurrentWorkOnRoot
функцияscheduleCallback
Функция запланирована, и логика после конкретного возврата должна перейти кScheduler
модуль для поиска
pop(taskQueue)
var callback = currentTask.callback;
if (typeof callback === 'function') {
...
} else {
pop(taskQueue);
}
вышеScheduler
внутри модуляworkLoop
фрагмент кода для функции,currentTask.callback
то естьscheduleCallback
Второй параметр , которыйperformConcurrentWorkOnRoot
функция
В продолжение предыдущей темы, еслиperformConcurrentWorkOnRoot
Функция вернула ноль,workLoop
будет выполняться внутриpop(taskQueue)
, измените текущую задачу сtaskQueue
Во всплывающем окне.
Перезапуск задачи с низким приоритетом
На предыдущем шаге было сказано, что задача с низким приоритетом начинается сtaskQueue
выбрасывается. Как после выполнения задачи с высоким приоритетом перезапустить предыдущую задачу с низким приоритетом?
Ключ вcommitRootImpl
функция
var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
markRootFinished(root, remainingLanes);
...
ensureRootIsScheduled(root, now());
markRootFinished
Только что упомянутая выше функция освобождает дорожку, занятую завершенной задачей, а это означает, что незавершенная задача по-прежнему будет занимать свою дорожку, поэтому мы можем вызвать ее снова.ensureRootIsScheduled
Запустите новое расписание, чтобы перезапустить выполнение низкоприоритетных задач. Мы можем перезапустить часть решения
var nextLanes = getNextLanes(
root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes
);
// 如果 nextLanes 为 NoLanes,就证明所有任务都执行完毕了
if (nextLanes === NoLanes) {
...
root.callbackNode = null;
root.callbackPriority = NoLane;
// 只要 nextLanes 为 NoLanes,就可以结束调度了
return;
}
// 如果 nextLanes 不为 NoLanes,就代表还有任务未执行完,也就是那些被打断的低优先级任务
...
проблема голодной миссии
Как упоминалось выше, после выполнения задачи с высоким приоритетом будет перезапущена задача с низким приоритетом, но если есть задачи с высоким приоритетом, которые продолжают поступать, разве моя задача с низким приоритетом не перезапускается?
Так что реагируйте, чтобы разобраться с проблемой решения голодных задач, реагируйте вensureRootIsScheduled
Когда функция запускается, выполняется следующая обработка: (см.markStarvedLanesAsExpired
функция)
var lanes = pendingLanes;
while (lanes > 0) {
var index = pickArbitraryLaneIndex(lanes);
var lane = 1 << index;
var expirationTime = expirationTimes[index];
if (expirationTime === NoTimestamp) {
if ((lane & suspendedLanes) === NoLanes || (lane & pingedLanes) !== NoLanes) {
expirationTimes[index] = computeExpirationTime(lane, currentTime);
}
} else if (expirationTime <= currentTime) {
root.expiredLanes |= lane;
}
lanes &= ~lane;
}
- Пройдите 31 трек, чтобы определить, соответствует ли время истечения срока действия каждого трека.
NoTimestamp
, если да, и на треке есть задачи для выполнения, инициализировать время истечения для трека - Если у дорожки есть время истечения, и время истечения меньше текущего времени, значит, срок действия задачи истек, и текущий приоритет нужно объединить в
expiredLanes
, так что в следующем раунде фазы рендеринга текущийHostRoot
Вы можете обратиться к функции, выполняемой на этапе рендеринга.performConcurrentWorkOnRoot
фрагмент кода в
var exitStatus = shouldTimeSlice(root, lanes) && ( !didTimeout) ?
renderRootConcurrent(root, lanes) :
renderRootSync(root, lanes);
можно увидеть, покаshouldTimeSlice
Пока он возвращает false, он будет выполнятьсяrenderRootSync
, то есть войдите в фазу рендеринга с синхронным приоритетом. а такжеshouldTimeSlice
Логика простоexpiredLanes
связанный с атрибутом
function shouldTimeSlice(root, lanes) {
// 如果 expiredLanes 里面有东西,代表有饥饿任务
if ((lanes & root.expiredLanes) !== NoLanes) {
return false;
}
var SyncDefaultLanes = InputContinuousHydrationLane |
InputContinuousLane |
DefaultHydrationLane |
DefaultLane;
return (lanes & SyncDefaultLanes) === NoLanes;
}
Суммировать
react
Механизм приоритета не является независимым и несвязанным модулем в исходном коде, а включает в себя все аспекты общей работы реакции Наконец, мы возвращаемся к разбору использования механизма приоритета в исходном коде, чтобы каждый мог иметь лучшее понимание механизма приоритета общее восприятие.
- разрезание времени. Включение прерывания задачи, расчет продолжительности фрагментации в соответствии с приоритетом
- setState генерирует объект Update. Каждый объект обновления имеет атрибут полосы, который представляет приоритет обновления.
- Задачи с высоким приоритетом прерывают задачи с низким приоритетом. Каждое планирование будет сравнивать текущую задачу с наивысшим приоритетом текущей задачи.Если они не равны, это означает, что поступает задача с высоким приоритетом, и текущую задачу необходимо прервать.
- 低优先级任务重启。 координация
(reconcile)
Следующий этап — рендеринг(renderer)
, что мы называем фазой фиксации. В конце этой фазы он вызоветensureRootIsScheduled
Инициируйте новое расписание для выполнения ожидающих выполнения задач с низким приоритетом. - Просыпается голодная миссия. В начале каждого планирования он сначала проверяет, есть ли задачи с истекшим сроком действия, и если они есть, в следующий раз будет синхронный приоритет.
(reconcile)
, приоритет синхронизации является наивысшим приоритетом и не будет прерываться
В конце концов, общая карта разума реакции разобрана, модуль планировщика в основном разобрался, а остальное будет сосредоточено на фазе рендеринга и фазе фиксации.