Взгляните на исходный код реакции с первого взгляда (1): почувствуйте эволюцию реакции

внешний интерфейс React.js
Взгляните на исходный код реакции с первого взгляда (1): почувствуйте эволюцию реакции

написать впереди

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

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

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

Почему react15 нужно развиваться?

У React15 есть два первородных греха: блокировка рендеринга и невозможность объединить setState в асинхронных функциях.

Первородный грех 1: синхронный рендеринг блокирует основной поток

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

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

疑问:react15什么情况下会造成阻塞?

реакция15 использует树形结构的虚拟DOM树,использовал递归Метод обхода узла, рекурсии означает, что построение виртуального DOM-дерева представляет собой синхронный процесс, который нельзя прервать, пока он запущен. И чем глубже уровень узла DOM и чем больше узлов, тем дольше процесс diff занимает поток JS.

Конечно, это то, что говорится в Интернете.На самом деле, действительно ли это древовидная структура?Это действительно рекурсивный способ обхода узлов?Его еще нужно проверить реальным исходным кодом.react@15.5.3исходный код

Доказательство 1: Структура деревьев

<div key={'最外层节点'}>
  {
    ['a', 'b', 'c', 'd'].map( (v,index) =>
      <div key={`第一层子节点 - ${v}`}>
        <span key={`${v}的子节点`}>parentNode:{v}</span>
      </div>
    )
  }
</div>

Приведенный выше код, когда JSX в дереве DOM проходит через структуру слоя дерева

react15树形结构.png

Доказательство 2: рекурсивный обход

Это моделируется в виде псевдокодаreact15Обход узлов определенного диапазона уровней вызовов исходного кода велик, и код нелегко анализировать.Заинтересованные студенты могут просмотреть реальный исходный код, чтобы просмотреть конкретные детали.

 function 构建节点(节点) {
    if (有子节点) return 生成子节点(节点)
    return 节点
  }
  function 生成子节点(children) {
    const 子节点列表 = []
    children.map(child => {
      子节点列表.push(构建节点(child))
    })
    return 子节点列表
  }
  function 挂载节点(node) {
    container.insertBefore(node)
  }
  function Render(组件, container) {
    const 应用根节点 = 组件()
    const 节点树 = 构建节点(应用根节点)
    挂载节点(节点树, container)
  }

  function Count(params) {
    return <div>1<div>
  }
  Render(<Count/>, document.querySelector('#root'))

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

Первородный грех 2: невозможно объединить setState внутри асинхронных функций

В дополнение к блокировке, в соответствии с реакцией15setStateМеханизм обновления основан на комбинированной функции как единое целое, внутренняя функция同步реализованоsetStateСлияние, заметьте, выполняется синхронноsetState, так что будет проблема, в асинхронной функцииsetStateНе удалось объединить.

  • Проблема 1: В асинхронных функцияхsetStateОбновления представлены синхронно
  • Вопрос 2: Все внутри асинхронной функцииsetStateвызовет полное обновление представления, что приведет к потере производительности

Ниже код проблемы

state = { count: 0 }
setCount() {
    this.setState({ count: 1 })
    console.log(this.state.count) // 输出0,这里是正常的,state不会马上更新
    setTimeout(() => {
        this.setState({ count: 2 })
        console.log(this.state.count) // 输出2,state同步更新,没有被合并
    })
}

Почему приведенный выше код выводит такой результат,react15Как работает обновление слияния? ?

Продайте, я отвечу вам в следующем цикле статей, расскажу вам с 30 строками кодаreact15Принцип обновления слиянием

Какие улучшения были сделаны, чтобы реагировать на архитектуру Fiber

решатьreact15Больная точка, после версии 16+,reactПерепишите всю архитектуру, чтобы реализовать асинхронные прерываемые обновления. Слова асинхронное прерываемое обновление просты, так как же вам нужно это реализовать?

рассмотрениеreact15две основные болевые точки, нам нужно решить две вещи

  1. Решить проблему с блокировкой.
  2. Пусть setState также будет объединен с асинхронными функциями.

Эти две проблемы будут решены одна за другой ниже

Решить проблемы с блокировкой

читать вышеreact15Псевдокод обхода узла, нетрудно найти, что есть два источника блокировки

  1. Рекурсивный обход дерева узлов без прерывания обхода
  2. Обход дерева узлов всегда будет занимать основной поток, блокируя другие потоки браузера.

解决手段1:改变树结构和节点遍历方式

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

Чтобы добиться прерываемого обхода, это легко сделать, вместо рекурсии используйтево время прохожденияЕсли запрос на прерывание удовлетворен

Но древовидную структуру делать не удобноwhileОбход, глубокая вложенность и много ответвлений, как исправить?

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

Ниже я кратко моделирую вид псевдокодаreact16+обход

let 需要被遍历的幸运儿节点 = null
function 构建节点() {
    /**
     *  ...在这里进行节点构建工作
     */
    需要被遍历的幸运儿节点 = 需要被遍历的幸运儿节点.next
}
function 节点遍历() {
    while (需要被遍历的幸运儿节点 != null) {
        构建节点()
    }
}
function 调度() {
    需要被遍历的幸运儿节点 = react应用根节点
    节点遍历()
}
调度()

Уведомление,Удачный узел, который нужно пройти = Удачный узел, который нужно пройти., react не просто использует next для описания отношения узла, я подробно опишу его в следующей серии статей

解决手段2:时间分片

Ну наконец-то реализованы прерываемые обновления, и мы на полпути.react16Так вот, остался еще один асинхронник, как его сделать? Пришло время нарезать

Time slicing, как следует из названия, заключается в установке фиксированного и непрерывного интервала времени с интервалами (кажется, не так, как следует из названия)

Что исправлено? Это я каждый деньрыба8 часов работы

Что такое непрерывный? Мне нужно ходить на работу каждый день

Что такое интервал? выходной

существуетreactиз时间分片соответствует

  1. Нарежьте фиксированное время около 5 мс (колеблются в соответствии с приоритетом, будет жить)
  2. Разделить прерывание и открытие работы React (фактически воздействуя только на часть работы)
  3. Между шардингом и шардингом есть интервал, который позволяет браузеру иметь время простоя для обработки задач других потоков.

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

下一章再讲吧,一下子写太多怕消化不了(逃

Интуитивное отражение разделения времени на производительность (в основном контролируется примерно на 5 миллисекундах)

时间分片.png

Пусть setState будет объединен с асинхронными функциями

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

Здесь я кратко описываю принцип реализации

  1. каждое исполнениеsetState

    А. Свяжите приоритет этого обновления с текущим узлом Fiber и корневым узлом Fiber.

    б. Выполнение функции планирования

  2. Функция планирования сначала выполнит логическое суждение, чтобы определить, равен ли приоритет текущего корневого узла приложения текущему запланированному приоритету.

    А. Равный. Это setState той же функции, которую можно объединять и обновлять без повторения задачи координации.

    б) не равно Инициировать координационную задачу

Здесь есть два случая неравенства: один — когда планирование инициируется впервые, а другой — когда появляется задача с высоким приоритетом.

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

Понять новую архитектуру реакции с точки зрения макросов

Первая часть серии в основном для пониманияreact16+Исходный код — это предвестие предварительного знания, чтобы каждый мог понятьreact16+Существует общее понимание состава , следующееreact16+Схема распределения функций модуля

react.png

Scheduler

Планировщик в основном отвечает за планирование задач реагирования, включая планирование сегментов и приоритетное планирование.

  • 分片调度Основная задача – нести ответственность заreconcile (render)Этапы могут периодически выполнять задачи обхода узла.

  • 优先级调度Основная цель состоит в том, чтобы разделить задачи реагирования на несколько типов приоритетов, чтобы задачи с высоким приоритетом могли реагировать быстро.

Reconciler

Reconciler в основном отвечает за построение узлов Fiber и создание соответствующих побочных эффектов.

  • state计算После введения механизма приоритета не просто прикрыть расчет состояния, что связано с логикой перезапуска низкоприоритетных задач

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

  • 副作用创建Запишите узлы, которые необходимо добавить, удалить и изменить, в атрибуте flags узла Fiber в виде операции битового И и дождитесь фазы фиксации, чтобы устранить эти побочные эффекты (побочные эффекты включают, но не ограничиваются добавление узлов, удаление и выполнение useEffect, обновления ссылок и т. д. Побочные эффекты)

Renderer

Renderer (commit)Что делает этап, так это очищает побочные эффекты, а затем начинает следующий раунд планирования.

Выше приведен базовый состав реакции и обязанности каждого модуля. В дальнейшем для облегчения интерпретации я буду использоватьrender阶段От имени тогоReconciler,использоватьcommit阶段От имени тогоRenderer

напиши в конце

В данной статье кратко описываетсяreactэволюционная история и новыеreactОсновные компоненты архитектуры. Далее я расскажу о реакции时间分片, при совмещенииreactзадачи для моделирования запущенного процесса с разделением по времени.

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

Наконец, я хотел бы поблагодарить г-на Касонгку за егоРаскрыта технология React, который мне очень помог в чтении исходного кода, Мистер Ка действительно силен (товаров не везу).