[Золото Три Серебро Четыре] React Интервью Часто Задаваемые Вопросы

React.js опрос
[Золото Три Серебро Четыре] React Интервью Часто Задаваемые Вопросы

Недавно команда набрала людей, поэтому я подготовил несколько основных вопросов для интервью.Если вам интересно, вы можете оставить сообщение, и я обновлю его~~~

Реклама, вы голодны? Команда фронтенда по заказу еды продолжает набирать людей~~~ Заинтересованное личное я~~~

Каковы различные способы создания компонентов в реакции? Какая разница

В React есть три способа сборки компонентов

  • React.createClass
  • ES6 class
  • функция без сохранения состояния

React.createClass — самый традиционный и совместимый метод React. Этот метод создает объект компонента, и при вызове компонента создается несколько экземпляров компонента.

Метод класса ES6 похож на createClass, за исключением того, что он реализуется классом вместо вызова внутренних методов.

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

Кратко опишите жизненный цикл React? Что делает каждый жизненный цикл?

Жизненный цикл React делится на три этапа: MOUNTING, RECEIVE_PROPS, UNMOUNTING.

  • Когда компоненты установлены (инициализация состояния компонента, прочитайте исходное состояние и реквизиты и два метода жизненного цикла, только при инициализации)
    • componentWillMount будет вызываться перед рендерингом (здесь вызов setState не вызовет повторный рендеринг, а объединит состояние. Поэтому this.state на данный момент не является последним, и обновленное this можно получить только в render..state.)
    • componentDidMount будет вызываться после рендера
  • Когда компонент обновляется (процесс обновления компонента относится к серии действий обновления, которые происходят, когда родительский компонент передает реквизиты или сам компонент выполняет метод setState)
    • Состояние самого компонента обновляется, выполняется последовательно
      • shouldComponentUpdate (получит реквизиты и состояние, которые необходимо обновить, пусть разработчик добавит необходимые условия суждения, обновит, когда нужно, и не обновит, когда не нужно. Если возвращает false, то компонент больше не будет выполняться жизненный цикл вниз. метод.)
      • componentWillUpdate
      • рендеринг (можно получить последнюю версию this.state)
      • ComponentDidupdate (может получить последнее значение.
    • Родительский компонент обновляет свойства и обновляет
      • componentWillReceiveProps (вызов setState здесь не вызовет повторный рендеринг, а объединит состояние. Следовательно, this.state на данный момент не является последним, и обновленное this.state можно получить только при рендеринге.
      • shouldComponentUpdate
      • componentWillUpdate
      • render
      • componentDidUpdate
  • Когда компонент удален
    • componentWillMount (мы часто выполняем некоторые методы очистки во время выгрузки компонента, такие как повторение событий, очистка таймеров)

image.png

Новая версия функции жизненного цикла добавляет getDerivedStateFromProps, Этот жизненный цикл фактически отображает входящие реквизиты в состояние. После React 16.4 эта функция будет вызываться каждый раз перед повторным рендерингом,

image.png

Роль getDerivedStateFromProps заключается в следующем.

  • Безоговорочно обновлять внутреннее состояние в соответствии с реквизитом, то есть, пока есть входящее значение реквизита, обновлять состояние
  • Значение состояния обновляется только в том случае, если значение свойства и значение состояния отличаются.

Но слепое использование этого жизненного цикла будет иметь некоторые проблемы

  • Скопируйте реквизит непосредственно в состояние
  • Обновить состояние, если свойства и состояние несовместимы

В каком жизненном цикле DOM фактически добавляется в HTML?

компонентDidMount, компонентDidUpdate

что происходит после обновления состояния

После обновления состояния последовательно выполняются shouldComponentUpdate, componentWillUpdate, render и componentDidMount. shouldComponentUpdate получит реквизиты и состояние, которые необходимо обновить, что позволит разработчикам добавлять необходимые условия суждения, обновлять, когда им это нужно, и не обновлять, когда это не нужно. Если возвращается false, компонент больше не будет проходить через методы жизненного цикла.

Является ли setState действительно асинхронным?

«Асинхронность» setState не означает, что он реализован асинхронным кодом внутри, на самом деле процесс и код, исполняемый сам по себе, синхронны, но последовательность вызова синтетических событий и hook() предшествует обновлению, что приводит к сбой синтетических событий и функций ловушек. Немедленно получить обновленное значение, в виде так называемого «асинхронного»,

Конечно, вы можете получить обновленный результат через второй параметр setState(partialState, callback).

setStateявляется "асинхронным" только в синтетических событиях и hook(), вРодные события иsetTimeoutЧжундуСинхронизироватьиз.

что происходит после setState

Простая версия:React использует механизм очереди состояний для реализации «асинхронного» обновления setState, избегая частых и повторяющихся обновлений состояния.

Сначала объедините новое состояние с очередью обновления состояния, а затем решите, нужно ли обновлять компонент, в соответствии с очередью обновления и состоянием shouldComponentUpdate.

Сложный вариант:

  1. enqueueSetState помещает состояние в очередь и вызывает enqueueUpdate для обработки компонента для обновления.
  2. Если компонент в настоящее время находится в транзакции обновления, сначала сохраните компонент в dirtyComponent. В противном случае вызовите обработку batchedUpdates.
  3. batchedUpdates инициирует транзакцию transaction.perform()
  4. Начать выполнение инициализации транзакции, запустить и завершить три фазы
    1. Инициализация: на этапе инициализации транзакции нет зарегистрированного метода, поэтому нет метода для выполнения.
    2. Run: метод обратного вызова, переданный при выполнении setSate
    3. Конец: Обновите isBatchingUpdates до false и выполните метод close в оболочке FLUSH_BATCHED_UPDATES. На этапе закрытия FLUSH_BATCHED_UPDATES будет перебирать все грязные компоненты, вызывать updateComponent для обновления компонента и выполнять его pendingCallbacks, который является обратным вызовом, установленным в setState.

IMG_0189.jpg

Что происходит, когда вы используете setState в shouldComponentUpdate или componentWillUpdate?

При вызове setState новое состояние фактически добавляется в очередь обновления состояния, а очереди обновления partialState и _pendingStateQueue объединяются. Наконец, обновление состояния выполняется через enqueueUpdate.

Если вы используете setState в shouldComponentUpdate или componentWillUpdate, очередь состояний (_pendingStateQueue) не будет нулевой, поэтому будет вызываться метод updateComponent, а вызовы shouldComponentUpdate и componentWillUpdate будут продолжать вызываться в updateComponent, что приведет к бесконечному циклу.

Почему вы не можете напрямую использовать this.state для изменения данных

setState реализует обновления состояния через механизм очереди. При выполнении setState состояние, которое необходимо обновить, будет объединено и помещено в очередь состояний без немедленного обновления this.state. Механизм очереди может эффективно обновлять состояние пакетами. Если this.state изменяется напрямую без setState, состояние не будет помещено в очередь состояний. изменять состояние, что приводит к непредсказуемым ошибкам.

Как оптимизировать компоненты без состояния без метода shouldComponentUpdate?

Поскольку компоненты без сохранения состояния не имеют жизненного цикла, отсутствует и shouldComponentUpdate. shouldComponentUpdate, чтобы избежать нежелательных повторных рендеров.

Таким образом, компоненты без сохранения состояния каждый раз перерисовываются. Некоторые компоненты будут иметь некоторые ненужные потери в производительности. Мы можем обратиться к чистому методу библиотеки Recompose. (На самом деле чистый метод заключается в преобразовании компонентов без состояния в компоненты с синтаксисом класса плюс PureRender)

Что вы делали после setState, когда вы должны использовать setState, выполнить setState в componentWillMount, componentDidMount

React DOM

Как вставлять компоненты прямо под корпус

Используя портал, портал заключается в создании «портала», чтобы такие компоненты, как Диалог, ничем не отличались от других компонентов уровня представления, но отображаемые вещи появлялись в другом месте, как если бы они прошли через портал.

До версии v16 это было реализовано с помощью нестабильного API_renderSubtreeIntoContainer. Глядя на название с нестабильной, вы понимаете, что это API, который не рекомендуется использовать, но для решения проблемы его все же нужно использовать. Функция этого API аналогична рендерингу, который заключается в обновлении компонента для входящего узла DOM.Используя его, мы можем реализовать межкомпонентные операции DOM внутри компонента.

Как мы видим в исходном коде, разница между методом нестабильного_renderSubtreeIntoContainer и методом рендеринга заключается в том, что нестабильное_renderSubtreeIntoContainer будет проходить в родительском узле, в то время как параметр рендеринга имеет значение null.

После v16 вы можете использовать метод createPortal во время рендеринга.

render() {
    return createPortal(
      <div class="dialog">
        {this.props.children}
      </div>, //塞进传送门的JSX
      this.node //传送门的另一端DOM node
    );
  }

Что такое ссылка в React?

Получить его с помощью refs. При вызове компонента создается новый экземпляр компонента. refs будет указывать на этот экземпляр, который может быть функцией обратного вызова, которая будет выполняться сразу после монтирования компонента.

Если мы поместим refs на вход нативных компонентов DOM, мы сможем получить узлы DOM через refs; если мы поместим refs в компоненты React, то получим экземпляр компонента, поэтому мы можем вызвать метод экземпляра (если мы хотим для доступа к реальному DOM компонента, то можно использовать React.findDOMNode для поиска узла DOM, но этот метод не рекомендуется).

refs нельзя использовать для компонентов без состояния.Когда компонент без состояния монтируется, это всего лишь вызов метода, и новый экземпляр не создается. После v16 можно использовать useRef.

Как реализован виртуальный дом реагирования?

React преобразует настоящее дерево DOM в дерево объектов JS, которое является виртуальным DOM. После каждого обновления данных ВМ пересчитывается и сравнивается с деревом ВМ, сгенерированным в последний раз, а измененные части обновляются пакетами. Помимо производительности, самым большим преимуществом реализации виртуальной машины является интеграция с другими платформами.

Например, наш настоящий DOM выглядит так

<button class="myButton">
  <span>this is button</span>
</button>

Затем после преобразования в виртуальную машину это так

{
  type: 'button',
  props: {
  	className: 'myButton',
    children: [{
      type: 'span',
      props: {
        type: 'text'
        children: 'this is button'
      }
    }]
  }
}
  

Почему виртуальные машины повышают производительность?

Поскольку виртуальная машина на самом деле не работает с DOM, можно избежать некоторых инвариантных операций с DOM с помощью алгоритма сравнения, тем самым повысив производительность.

Обязательно ли виртуальные машины улучшают производительность?

Не обязательно, потому что виртуальная машина избегает только некоторых операций DOM, которые не нужно изменять с помощью алгоритма сравнения, и в конечном итоге должна работать с DOM, а процесс сравнения также имеет стоимость.

В некоторых сценариях, таких как операции, требующие изменения DOM, поскольку виртуальная машина также требует дополнительного алгоритма сравнения, подход виртуальной машины не улучшит производительность, даже медленнее, чем собственный DOM.

Но, как сказал Юда, это компромисс между производительностью и ремонтопригодностью. Смысл фреймворка в том, чтобы замаскировать для вас базовые манипуляции с DOM, позволяя вам описать свою цель более декларативным способом, тем самым упрощая поддержку вашего кода. Ни один фреймворк не может оптимизировать операции DOM быстрее, чем чисто ручные операции, потому что уровень манипулирования DOM фреймворка должен иметь дело с любыми операциями, которые могут быть сгенерированы API верхнего уровня, и его реализация должна быть универсальной. Я могу написать ручную оптимизацию быстрее, чем любой фреймворк для любого бенчмарка, но какой в ​​этом смысл? При создании реального приложения вы все оптимизируете вручную? По соображениям ремонтопригодности это, очевидно, невозможно. Гарантия, которую дает фреймворк, заключается в том, что вам не нужно

Краткое введение в алгоритм diff

Алгоритм diff в основном имеет три стратегии (закон наблюдения)

  • Межуровневое перемещение узлов DOM происходит очень редко и может быть проигнорировано.
  • Два компонента с одним и тем же классом будут генерировать похожие древовидные структуры, а два компонента с разными классами будут генерировать разные древовидные структуры.
  • Группу дочерних узлов одного уровня можно отличить по уникальному идентификатору.

tree diff

Из-за первого пункта в трех вышеприведенных стратегиях межуровневая операция узлов DOM относительно невелика, поэтому алгоритм сравнения будет сравнивать только узлы DOM одного уровня. Если обнаружится, что узел не существует, узел и его дочерние узлы будут полностью удалены, и сравнение не будет продолжаться. Если есть операция перемещения узла DOM между уровнями, узел и все его дочерние узлы будут удалены, а затем воссозданы в перемещенной позиции.

component diff

Если это однотипный компонент, то продолжайте сравнивать количество ВМ Если это компонент другого типа, он будет полностью заменен своими дочерними узлами и больше не будет сравниваться. Для одного и того же типа компонента в ВМ может не быть изменений.Если вы знаете это наверняка, вы можете сэкономить много времени на сравнение, поэтому пользователь может установить shouldComponentUpdate(), чтобы определить, должен ли алгоритм сравнения быть выполнено.

element diff

Когда узлы находятся на одном уровне, есть три операции: вставка INSERT_MAKEUP, перемещение MOVE_EXISTING, удаление REMOVE_NODE. Здесь у React есть стратегия оптимизации: для одной и той же группы дочерних узлов на одном уровне добавляется уникальный ключ, чтобы различать их. В этом случае можно судить, является ли это мобильным узлом. По ключу выясняется, что узлы в старом и новом наборах являются одним и тем же узлом, и требуется только операция перемещения. Конечно, стратегия оптимизации и конкретный метод diff здесь все еще очень сложны, поэтому я не буду ее расширять.

в реактивном маршрутизаторе<Link>этикетки и<a>Чем отличаются этикетки

В сравнении<a>Этикетка,LinkИзбегайте ненужного повторного рендеринга

react-router — это система маршрутизации, появившаяся вместе с фреймворком react, и она также признана отличным решением для маршрутизации. При использовании react-router мы часто используем свой собственный компонент перехода по пути Link, реализуя jump;

Реакция-маршрутизатор берет на себя поведение перехода по ссылке по умолчанию.В отличие от традиционного перехода страницы, поведение «перехода» ссылки вызывает только обновление соответствующего содержимого страницы без обновления всей страницы.

Переходы по ссылкам делают три вещи:

  1. Если есть onclick, выполнить onclick
  2. Предотвратить событие тега по умолчанию при нажатии
  3. По адресу перехода используйте историю для перехода.На данный момент изменилась только ссылка, а страница не обновлялась

Тег a — это обычная гиперссылка, используемая для перехода с текущей страницы на другую страницу, на которую указывает href (случай без привязки).

Система событий в React

Кратко опишите механизм делегирования событий React?

React не привязывает все обработчики напрямую к реальным узлам. Вместо этого все события привязываются к самому внешнему слою структуры, и используется унифицированный прослушиватель событий, который поддерживает карту для сохранения функций мониторинга и обработки событий внутри всех компонентов.

Просто вставьте или удалите некоторые объекты в этом унифицированном прослушивателе событий, когда компонент монтируется или размонтируется.

Когда происходит событие, оно сначала обрабатывается этим унифицированным прослушивателем событий, а затем на карте находится и вызывается реальный обработчик события.

Преимущество этого заключается в том, что он решает проблемы совместимости и упрощает обработку и повторное использование событий (нет необходимости вручную отвязывать события, React уже обрабатывает это внутри). Но некоторые события не реализованы в React, например, событие изменения размера окна.

В чем разница между механизмом делегирования событий React и собственной привязкой событий?

  1. Распространение событий и предотвращение распространения событий. Синтетические события React не реализуют захват событий, а поддерживают только всплывающие потоки событий. Предотвращение распространения событий React выполняет обработку совместимости, просто нужноe.preventDefault()Все, есть проблемы с родной совместимостью.
  2. Тип события: React — это подмножество собственных типов событий (React реализует только интерфейс событий уровня DOM 3, а некоторые события React не реализует, например, событие изменения размера окна). используется для синтеза React Система событий, но всплывающее поведение в нативных событиях предотвращает распространение синтетических событий React.
  3. Методы привязки событий: собственная система событий поддерживает множество различных способов привязки событий, а в React есть только один.
  4. Объект события: существует проблема совместимости с IE в нативном режиме, и React выполнил обработку совместимости.

Что плохого в смешивании механизма делегирования событий React с нативной привязкой событий?

Мы должны избегать смешивания механизма прокси-сервера событий React и нативной привязки событий в нашей обычной разработке.

Слой синтетических событий React не связывает события напрямую с элементами DOM, поэтому используйтеe.stopPropagation()Чтобы остановить всплывающее поведение нативного DOM, этого недостаточно. Поведение предотвращения всплытия событий React можно использовать только в системе синтетических событий React, но поведение предотвращения всплытия в собственных событиях может предотвратить распространение синтетических событий React.

Что произойдет, если вы привяжете события с помощью анонимных функций в React

class Demo {
  render() {
    return <button onClick={(e) => {
      alert('我点击了按钮')
    }}>
      按钮
    </button>
  }
}

Таким образом, поскольку используется анонимная функция, компонент каждый раз будет рассматриваться как новый реквизит, а оптимизация кеша не будет использоваться, что приведет к определенной потере производительности.

Связь между компонентами React

  • Родительский компонент общается с дочерним компонентом: реквизит
  • Дочерний компонент взаимодействует с родительским компонентом: функция обратного вызова
  • Взаимодействие между компонентами: контекст
  • Взаимодействие компонентов без отношения вложенности: eventEmitter, который использует глобальные объекты для сохранения событий и использует широковещательную рассылку для обработки событий.

оптимизация производительности

Какие оптимизации производительности можно сделать в React?

  • Используйте ShouldComponentUpdate, чтобы избежать нежелательного рендеринга, но если prOPs и State глубоко сравниваются, цена велика, поэтому вам нужно сделать некоторую оплату в соответствии с бизнесом; в случае с подкомпонентами, чтобы избежать повторного рендеринга подкомпонентов , вы можете передать родительские компоненты, чтобы определить, нужен ли PureRender подкомпонентам.
  • Установите реквизиты на массив или объект: при каждом вызывающем компонент React React будет создан, будет создан новый компонент. Даже если значение входящего массива или объекта не изменяется, их справочный адрес также изменится. Например, если следующее написано, то каждый раз стиль - новый объект при рендеринге
// 不推荐
<button style={{ color: 'red' }} />

// 推荐
const style = { color: 'red' }
<button style={style} />

// 不推荐
<button style={this.props.style || {} } />  

// 推荐
const defaultStyle = {}
<button style={this.props.style || defaultStyle } />   
  • Переместите привязку функции внутрь конструктора: вы можете избежать привязки события каждый раз.
  • Используя неизменяемые неизменяемые данные, при использовании ссылочных типов в нашем проекте, чтобы избежать влияния на исходные данные, обычно рекомендуется использовать для обработки данных мелкое копирование и глубокое копирование, но это приведет к трате ресурсов ЦП и памяти, поэтому рекомендуется использовать неизменяемый, преимущества следующие
    • Уменьшенная сложность, вызванная «переменной»
    • Для экономии памяти неизменяемый использует совместное использование структуры для максимально возможного повторного использования памяти, а объекты, на которые нет ссылок, будут удалены сборщиком мусора.
    • Улучшенная отмена/повтор, копирование/вставка, путешествия во времени
    • Не будет проблем с параллелизмом (поскольку сами данные неизменяемы)
    • Займитесь функциональным программированием
  • Установите уникальный ключ для дочернего компонента, потому что в алгоритме diff ключ будет использоваться как уникальный идентификатор для оптимизации рендеринга.

Почему вы хотите установить ключ для компонента

В процессе разработки нам необходимо убедиться, что элементkeyУникальный среди своих собратьев. существует React Diffв алгоритмеReactбудет использовать элементKeyзначение, чтобы определить, создан ли элемент заново или перемещен, тем самым уменьшая ненужную повторную визуализацию элемента. Кроме того, React также нуждается в помощиKeyзначение для определения связи между элементом и локальным состоянием.

HOOKS

реагирующие хуки, которые приносят эти удобства

Пока нет хуков, мы не можем использовать состояние React и характеристики различных хуков-подобных компонентов жизненного цикла в компонентах, определяемых функциями. После React 16.8 была введена новая функция: хуки, с помощью которых мы можем использовать функции компонентов класса в компонентах, определенных функциями.выгода:

  1. Межкомпонентное повторное использование: На самом деле, render props/HOC тоже предназначены для повторного использования.По сравнению с ними, Hooks, как официальный базовый API, являются наиболее легковесными, а стоимость преобразования низкая, что не повлияет на исходную иерархию компонентов и легендарный гнездовой ад;
  2. Определение класса более сложное
  • Различные жизненные циклы сделают логику разбросанной и запутанной, и ее будет непросто поддерживать и управлять;
  • Всегда нужно обращать внимание на указание проблемы этого;
  • Повторное использование кода обходится дорого, а использование компонентов более высокого порядка часто приводит к раздуванию всего дерева компонентов;
  1. Изоляция состояния и пользовательского интерфейса: именно из-за характеристик хуков логика состояния станет менее детализированной, и ее очень легко абстрагировать в пользовательские хуки, состояние и пользовательский интерфейс в компоненте станут более четкими и изолированными.

Уведомление:

  • Избегайте вызова хуков в циклах/оценках условий/вложенных функциях, чтобы обеспечить стабильность вызываемой последовательности;
  • Вы не можете использовать stestate в Use Expectect In, Rect получит приглашение ошибки;
  • Компоненты класса не будут заменяться или отбрасываться, нет необходимости принудительно преобразовывать компоненты класса, и эти два метода могут сосуществовать.

Перечислите несколько общих хуков

  • Хук состояния (useState): используется для определения состояния компонента, аналогично функции this.state в определении класса.
  • Хук жизненного цикла (useEffect): в определении класса есть много функций жизненного цикла, и соответствующая функция (useEffect) также предоставляется в хуках React, которые можно рассматривать как комбинацию componentDidMount, componentDidUpdate и componentWillUnmount.
  • useContext: получить объект контекста
  • useCallback: Кэшируйте функцию обратного вызова, чтобы входящий обратный вызов не был каждый раз новым экземпляром функции и вызывал повторную визуализацию зависимого компонента, что имеет эффект оптимизации производительности;
  • useMemo: Используется для кэширования входящих реквизитов, избегайте рендеринга каждый раз, когда он отображается каждый раз;
  • useRef: Получить реальный узел компонента;

Как useEffect в React Hooks отличает хуки жизненного цикла

useEffect можно рассматривать как >componentDidMount, >componentDidUpdateи >componentWillUnmountКомбинация трех. USEFFECT (обратный вызов, [источник]) получает два параметра и называется следующим образом

useEffect(() => {
   console.log('mounted');
   
   return () => {
       console.log('willUnmount');
   }
 }, [source]);

** 生命周期函数的调用主要是通过第二个参数[source]来进行控制,有如下几种情况:

  • [source]Когда параметры не передаются, функция, возвращенная в последней сохраненной функции, будет вызываться первой каждый раз, а затем будет вызываться внешняя функция;
  • [source]При передаче параметра [] внешняя функция будет вызываться только один раз при инициализации, а возвращаемая функция будет вызываться только один раз при выгрузке компонента;
  • [source]Когда параметр имеет значение, он будет вызывать возвращаемую функцию только после изменения значения в массиве, а затем вызывать внешнюю функцию.

принцип подключения

connect на самом деле является HOC, который обертывает слой исходного компонента приложения, превращая исходное приложение в целом вProviderПодкомпоненты приемаReduxизstoreтак какprops,пройти черезcontextобъект передается компонентам-потомкамconnect

перениматьmapStateToProps,mapDispatchToProps, затем возвращает продукциюComponentФункция(wrapWithConnect), то тогда будет реальноComponentПередать как параметрwrapWithConnect, тем самым создавая завернутыйConnectкомпоненты,

Волокно?

Официальное объяснение: React Fiber — это повторная реализация основного алгоритма. ** По мере того, как приложение становится все больше и больше, весь процесс рендеринга обновлений становится трудоемким, а большое количество рендеринга компонентов приведет к тому, что основной процесс будет занят в течение длительного времени, что приведет к некоторым анимациям или высокочастотным операциям. Ключевым моментом является блокировка синхронизации. В предыдущем алгоритме планирования React необходимо создать экземпляр каждого компонента класса, сгенерировать дерево компонентов и использовать синхронный рекурсивный метод для обхода и рендеринга.Самая большая проблема этого процесса заключается в том, что его нельзя приостановить и возобновить.

  • существуетReact V16Реконструкция алгоритма планирования, предыдущаяstack reconcilerРеконструировать новую версию волокнаreconciler, который становится алгоритмом обхода дерева односвязных списков со связанными списками и указателями. Благодаря отображению указателя каждый блок записывает предыдущий и следующий этап обхода, так что обход можно приостановить и перезапустить.
  • Здесь я понимаю это как алгоритм планирования разделения задач, который в основном делит исходные задачи синхронного обновления и рендеринга на независимые небольшие блоки задач и распределяет небольшие задачи на время простоя браузера в соответствии с разными приоритетами.Используйте механизм цикла событий основной процесс