Зачем нужен приоритет
Конечной целью механизма приоритета является достижениеЗадачи с высоким приоритетом выполняются первыми, а задачи с низким приоритетом выполняются позже..
Суть этого назначения в том, что при выполнении низкоприоритетной задачи, если приходит более высокоприоритетная задача, выполнение низкоприоритетной задачи может быть прервано.
Среда выполнения 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, но будет генерировать на основе содержимого setStateUpdateObject, этот объект содержит такие свойства, как содержимое обновления и приоритет обновления. - возобновить
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), приоритет синхронизации является наивысшим приоритетом и не будет прерываться
В конце концов, общая карта разума реакции разобрана, модуль планировщика в основном разобрался, а остальное будет сосредоточено на фазе рендеринга и фазе фиксации.