Анализ исходного кода React (3): подробная транзакция и очередь обновлений

внешний интерфейс исходный код JavaScript React.js внешний фреймворк
Анализ исходного кода React (3): подробная транзакция и очередь обновлений

В первых двух статьях мы проанализировали реализацию, монтаж и жизненный цикл компонентов React. В процессе чтения исходного кода мы часто видим такие вещи, какtransactionа такжеUpdateQueueТакой код, который включает в себя две концепции в React: транзакции и очереди обновлений. Поскольку мы рассмотрели их в предыдущих статьях, эта статья основана на том, что всем знакомо.setStateметоды для изучения механизмов транзакций и обновления очередей.

1.setState связан

в первой статье«Анализ исходного кода React (1): внедрение и установка компонентов»мы уже знаем, что поclassЗаявленный прототип компонента имеетsetStateметод:

Этот метод передает два параметраpartialStateа такжеcallBack, первое — это новое значение состояния, а второе — функция обратного вызова. а такжеupdaterопределяется в конструкторе:

Как можно заметитьupdaterОн передается конструктором, поэтому найдите, где его выполнить.new ReactComponent, ты можешь найтиupdaterчто. с пользовательскими компонентамиReactCompositeComponentНапример, в_constructComponentWithoutOwnerметод, мы нашли его следы:

return new Component(publicProps, publicContext, updateQueue);

Обнаружение соответствующего параметраupdaterНа самом деле этоupdateQueue. Далее посмотримthis.updater.enqueueSetStateсерединаenqueueSetStateЧто это:

getInternalInstanceReadyForUpdateЦель метода — получить текущий объект компонента и присвоить егоinternalInstanceПеременная. Затем оцените, существует ли очередь обновления состояния текущего объекта компонента, и если да, то она будетpartialStateТо есть в очередь добавляется новое значение состояния, если его нет, создается очередь обновления объекта, и можно отметить, что очередь существует в виде массива. Давайте посмотрим на последний звонокenqueueUpdateЧто делает метод:

Видно из кода, когдаbatchingStrategy.isBatchingUpdatesдляfalse, исполнитсяbatchedUpdatesочередь обновления, еслиtrue, поместите компонент вdirtyComponentсередина. Давайте посмотримbatchingStrategyИсходный код:

Грубо говоря, начальное значение isBatchingUpdates равноfalse,а такжеbatchedUpdatesВнутренне выполнить входящую функцию обратного вызова.

Кажется, что такая длинная логика немного сбивает с толку, но из этих кодов мы смутно понимаем, что React не обновляет компоненты случайно, а выполняет их через оценку состояния (например, true/false). На самом деле React использует концепцию «конечной машины» внутри: когда компоненты находятся в разных состояниях, логика выполняется по-разному. Взяв в качестве примера процесс обновления компонентов, React обновляет компоненты в форме транзакции + состояния, поэтому давайте обсудим механизм транзакций далее.

2. транзакция транзакция

Сначала посмотрите на диаграмму анализа официального исходного кода:

<pre>
 *                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | wrapper
 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 * </pre>

Из блок-схемы это очень просто, каждый метод будетwrapperупаковано, надо использоватьperformВызывается, выполняется до и после обернутого методаinitializeа такжеclose. Примеры обычных функций иwrapperВ чем разница, когда выполняется обернутая функция:

function method(){
    console.log('111')
};
transaction.perform(method);
//执行initialize方法
//输出'111'
//执行close方法

мы знаем, что предыдущийbatchingStrategyв кодеtransaction.perform(callBack)Фактический вызовtransaction.perform(enqueueUpdate),ноenqueueUpdateметод все еще существуетtransaction.perform(enqueueUpdate)Разве это не создает бесконечный цикл?

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

Как видно из приведенной выше ментальной карты,isBatchingUpdatesНачальное значениеfalse, когда выполняется как транзакцияtransaction.perform(enqueueUpdate), фактический поток выполнения выглядит следующим образом:

// RESET_BATCHED_UPDATES.initialize() 实际为空函数
// enqueue()
// RESET_BATCHED_UPDATES.close()

Используйте блок-схему, чтобы проиллюстрировать:

На словах этоRESET_BATCHED_UPDATESэтоwrapperРоль заключается в том, чтобы установитьisBatchingUpdatesТо есть значение состояния обновления компонента.Если у компонента есть запрос на обновление, он устанавливается в состояние обновления, а исходное состояние восстанавливается после завершения обновления.

Что хорошего в этом? Конечно, чтобы избежать повторения компонента рендеринга, улучшите его производительность ~

RESET_BATCHED_UPDATESДля измененияisBatchingUpdatesлогическое значениеfalseилиtrue,ЭтоFLUSH_BATCHED_UPDATESКакова роль? На самом деле можно примерно догадаться, что его роль заключается в обновлении компонентов.Давайте сначала разберемся.FLUSH_BATCHED_UPDATES.close()Логика реализации:

можно увидетьflushBatchedUpdatesМетод петлей через всеdirtyComponents, Но также в форме транзакции вызоваrunBatchedUpdatesметод, потому что исходный код длинный, поэтому вот две вещи, которые делает этот метод:

  • Один из них заключается в реализацииupdateComponentметод обновления компонента
  • Во-вторых, еслиsetStateЕсли функция обратного вызова передается в метод, функция обратного вызова сохраняется вcallbackQueueочередь.

посмотриupdateComponentИсходный код:

можно увидеть казненнымcomponentWillReceivePropsМетоды иshouldComponentUpdateметод. Одна из вещей, которую нельзя игнорировать, это то, чтоshouldComponentUpdateраньше, казненный_processPendingStateметод, давайте посмотрим, что делает эта функция:

Эта функция в основномstateОбрабатывать:
1. Если очередь обновленийnull, затем вернитесь к исходномуstate;
2. Если в очереди обновлений есть обновление, вернуть значение обновления;
3. Если в очереди обновлений несколько обновлений, объедините их с помощью цикла for;
Таким образом, в жизненном цикле объясняется,componentShouldUpdateПеред казнью всеstateИзменения будут объединены и, наконец, обработаны единообразно.

назад_updateComponent, и, наконец, еслиshouldUpdateдляtrue,воплощать в жизнь_performComponentUpdateметод:

После грубого просмотра вы обнаружите, что та же процедура все еще выполняется.componentWillUpdateМетод жизненного цикла, выполняемый после завершения обновленияcomponentDidUpdateметод. Давайте посмотрим на обновление_updateRenderedComponentметод:

Идея этого кода очень ясна:

  1. Получить информацию о старом компоненте
  2. Получить информацию о новом компоненте
  3. shouldUpdateReactComponentЭто метод (далее указанный какshouldФункция), определяется, обновлять ли старые и новые компоненты переданной информации.
  4. shouldвозврат функцииtrue, чтобы выполнить обновление старого компонента.
  5. shouldвозврат функцииfalse, который выполняет размонтирование старого компонента и монтирование нового компонента.

В сочетании с предыдущей блок-схемой мы дополняем весь процесс обновления компонентов:

4. Пишите в конце

(1)setStateПерезвоните

setStateфункция обратного вызова сstateПроцесс аналогичен,stateЗависит отenqueueSetStateобработка, функция обратного вызоваenqueueCallbackразобраться, заинтересованные читатели могут изучить самостоятельно.

(2) ОsetStateавария, вызванная

Мы уже знаем,this.setStateна самом деле называетсяenqueueSetState, когда компонент обновляется, потому что новыйstateОн еще не был объединен, поэтому следующееperformUpdateIfNecessaryв кодеthis._pendingStateQueueдляtrue:

СлияниеstateПосле того, как React будетthis._pendingStateQueueУстановить какnull,такdirtyComponentПри переходе к следующей пакетной обработке обновленные компоненты не войдут в повторный процесс, гарантируя, что компоненты выполнят операцию обновления только один раз.

так что не вcomponentWillUpdateвызыватьsetStateПричина в том, чтоsetStateзакажу_pendingStateQueueдляtrue, что приводит к повторному выполнениюupdateComponentПотом снова позвонюcomponentWillUpdate, последний цикл вызываетcomponentWillUpdateвызвать сбой браузера.

(3) О внедрении зависимостей React

В предыдущем коде у нас есть логотип очереди обновления.batchingStrategy, переходим непосредственно кReactDefaultBatchingStrategyАнализ, это из-за большого количества инъекций зависимостей внутри React. Когда React инициализируется,ReactDefaultInjection.jsвводить вReactUpdatesв качестве стратегии по умолчанию. Внедрение зависимостей имеет большое количество применений в рендеринге React на стороне сервера, и заинтересованные студенты могут изучить его самостоятельно.

рассмотрение:
«Анализ исходного кода React (1): внедрение и установка компонентов»
«Анализ исходного кода React (2): жизненный цикл компонентов»
«Анализ исходного кода React (4): система событий»
Контактный адрес электронной почты: sssyoki@foxmail.com