В первые дни страница рендерилась сервером, то есть технологиями PHP и JSP, сервер заполнял данные через шаблонизатор, возвращал сгенерированный html и передал браузеру для рендеринга. В это время форма будет отправлена синхронно, и сервер вернет html страницы результатов.
Позже в браузере появилась технология ajax, которая может запрашивать асинхронно, а сервер возвращает xml или json. Первоначально Ajax был основан на xml, откуда и произошло его название. Поскольку в xml много ненужных тегов и больше контента, json стал популярен позже.
Взаимодействие данных между веб-страницей и сервером стало асинхронным, сервер может возвращать json-данные, сплайсировать html в браузере, а затем рендерить (генерация dom в браузере эквивалентна рендерингу). В основном нет необходимости обновлять страницу, поэтому она постепенно превратилась в одностраничное приложение SPA (одностраничное приложение).
При разработке страниц в первые дни он был основан на dom API браузера для управления dom для рендеринга и взаимодействия, но dom API был более подробным, и проблемы совместимости браузеров в то время также были проблематичными, и разные браузеры имели разные способы письма. Для того, чтобы упростить работу с dom и сделать его более удобным для совместимости с различными браузерами, появился и быстро стал популярным jquery, в то время jquery был в самом разгаре.
Я всегда привык делить веб-страницы на физический уровень и логический уровень.Даже если dom — это физический уровень, jquery — это набор инструментальных функций для работы с dom, и он также работает на физическом уровне.
Веб-страница в основном получает данные для отображения DOM и обновляет DOM после изменения данных.Этот процесс является общим.Позже постепенно появилась структура mvvm для автоматического сопоставления изменений данных с DOM и никаких ручных операций. требуется DOM. То есть современные интерфейсные фреймворки, такие как vue и react. Я называю этот слой логическим слоем.
В дополнение к предоставлению функции управляемого данными изменения представления интерфейсная структура также поддерживает логическое разделение DOM, которое может инкапсулировать часть DOM в компоненты, и объединять компоненты и компоненты для формирования всего интерфейса. Физический уровень по-прежнему DOM, но после того, как реализовано автоматическое сопоставление данных с DOM, нам нужно только написать компоненты на логическом уровне.
Теперь внешний интерфейс больше не будет изучать jquery физического уровня для работы с домом, а начнет непосредственно с внешнего интерфейса логического уровня, такого как vue и react.
Но это не значит, что jquery вообще не нужен, front-end фреймворк в основном решает привязку данных к DOM, который умеет автоматически обновлять DOM после изменений. Если вам не нужно обновлять, вы можете напрямую управлять домом, например, различными активными страницами, обновления данных нет, по-прежнему очень удобно использовать jquery для управления домом.
Внешний фреймворк представляет собой декларативную идею UI = f(state).Вам нужно только объявить представление компонента, данные состояния компонента и зависимости между компонентами, тогда изменение состояния произойдет автоматически обновить ДОМ. И библиотека инструментов jquery, которая напрямую манипулирует dom, обязательна.
Для описания представления react и vue используют разные схемы.React расширяет синтаксис jsx до js и реализуется babel.При описании представления можно напрямую использовать js для написания логики, нового синтаксиса нет. Vue — это DSL, который реализует набор шаблонов, который вводит синтаксис шаблона, такой как интерполяция, директивы и фильтры.По сравнению с jsx, он более лаконичен.Компилятор шаблона реализован Vue.
Шаблон Vue ограничен, он может получать доступ только к данным, реквизиту, методу и может анализироваться и оптимизироваться статически, в то время как jsx реакции является непосредственно синтаксисом js и имеет много динамической логики, поэтому его нельзя анализировать и оптимизировать статически.
Однако с шаблоном vue не все хорошо, потому что он отделен от контекста js, в него сложнее ввести машинописный текст для вывода типов, и необходимо отдельно объявлять типы всех реквизитов, методов и данных. JSX реакции изначально имеет тот же контекст, что и js, и естественно комбинировать машинописный текст.
Так что шаблон vue и react jsx имеют свои преимущества и недостатки.
Фронтенд-фреймворки — это все изменения представления, управляемые данными, и эти данные разбросаны по каждому компоненту, как обновить dom после изменения данных?
По сути, есть только три способа обнаружения изменений данных: наблюдение, грязная проверка и отсутствие проверки.
Vue — это часы, основанные на данных.Уровень компонента прослушивает изменения в свойствах объекта через Object.defineProperty, переписывает API массива для прослушивания изменений в элементах массива, а затем обновляет dom.
Angular основан на грязной проверке: после каждой логики, которая может изменить данные, он сравнивает, изменились ли данные, и, если они меняются, обновляет DOM.
React не проверяет, рендерит ли он каждый раз весь DOM? Нет, не проверяется, потому что он не рендерится напрямую в dom, а добавляется слой виртуального dom посередине, который каждый раз рендерится в этот виртуальный dom, а потом изменился ли виртуальный dom, отрендеренный под диффом , и если да, то будет обновлен соответствующий dom.
Это три идеи изменения представлений на основе данных во интерфейсных фреймворках.
Vue — это просмотр данных на уровне компонента.Когда внутри компонента есть много мест для отслеживания изменений данных, обновление может потребовать много вычислений, а если вычисление слишком велико, это может привести к потере кадров, то есть рендеринг завис. Таким образом, метод оптимизации Vue состоит в том, чтобы разбить большие компоненты на маленькие компоненты, чтобы для каждых данных не было слишком много наблюдателей.
React не отслеживает изменения данных, а рендерит весь виртуальный DOM, а затем дифференцирует. Метод оптимизации, основанный на этой схеме, заключается в том, чтобы пропустить рендеринг через shouldComponentUpdate для компонентов, которым не нужно регенерировать vdom.
Однако, когда дерево компонентов приложения очень велико, просто shouldComponentUpdate пропускает отрисовку некоторых компонентов, что все равно может потребовать большого объема вычислений. Большой объем вычислений также может привести к зависанию рендеринга, что мне делать?
Обход дерева имеет два метода: сначала в глубину и сначала в ширину.Визуализация дерева компонентов выполняется сначала в глубину, что обычно выполняется с помощью рекурсии, но если путь можно записать через связанный список, он может превратиться в цикл. Если это становится циклом, то его можно сегментировать в соответствии с временными интервалами, чтобы генерация vdom больше не блокировала рендеринг страницы, точно так же, как планирование нескольких процессов с разделением времени операционной системой.
Эта функция изменения генерации vdom с рекурсии на цикл путем преобразования дерева компонентов в связанный список — это реакция волокна.
По сравнению с предыдущими компонентными узлами, волоконный узел не имеет родительских и дочерних атрибутов, но имеет дочерние, одноуровневые и возвращаемые атрибуты.
Оптимизирована производительность рендеринга благодаря дереву списков, связанных волокнами.
Видно, что оптимизация производительности vue отличается от оптимизации реакции:
Vue — это решение для мониторинга данных на уровне компонентов.Проблема может возникнуть, когда для свойства слишком много наблюдателей, поэтому идея оптимизации состоит в том, чтобы разбить большие компоненты на маленькие компоненты, чтобы гарантировать, что у каждого свойства не будет слишком много наблюдателей.
Реакт не отслеживает и не проверяет изменения данных, он каждый раз рендерит и генерирует вдом, а потом сравнивает вдом, далее идея оптимизации в том, чтобы пропустить рендеринг некоторых компонентов, а реакт так же делает связанный список дерева компонентов (файбера) внутри Чтобы изменить рекурсию на прерываемый рендеринг, постепенно сгенерируйте весь vdom в соответствии с временным интервалом.
Между компонентами должно быть логическое повторное использование.React и Vue имеют разные решения:
Компоненты Vue представлены в виде опциональных объектов, поэтому метод логического повторного использования можно, естественно, представить через миксин атрибутов объекта.Схема логического повторного использования в компонентах vue2 — это миксин, но миксин трудно отличить от источника смешанного атрибуты и методы, что беспорядочно. , ремонтопригодность кода оставляет желать лучшего. Но лучшего решения нет.
React также сначала поддерживал примеси, но позже от него отказались.
Компоненты React представлены в двух формах: класс и функция, поэтому способ компонентов высокого порядка, аналогичный функциям высшего порядка, более естественен, то есть компонент устанавливает компоненты, выполняет часть логики в родительском компоненте, а затем визуализирует дочерний компонент.
В дополнение к методу HOC добавления слоя компонентов, часть без логики может напрямую передавать эту часть jsx в качестве реквизита другому компоненту для повторного использования, то есть рендеринга реквизита.
HOC и render props — это две логические схемы повторного использования, поддерживаемые компонентами класса реакции.
Исходный функциональный компонент не имеет состояния и существует только как вспомогательное средство для рендеринга компонентов класса.
Однако метод повторного использования логики HOC в конечном итоге приводит к глубокой вложенности компонентов, и существует множество внутренних жизненных циклов класса, и логика объединяется, что приводит к относительно большому компоненту.
Как решить проблему глубокой вложенности компонентов класса и больших компонентов? И нельзя вводить разрушительное обновление, иначе конец может быть несчастным.
Итак, команда реагирования посмотрела на функциональный компонент, может ли он также поддерживать состояние в функциональном компоненте и поддерживать его, расширяя некоторые API, и это не деструктивное обновление.
Если функциональный компонент должен поддерживать состояние, то где оно существует?
У узла компонента класса есть состояние, и он все еще существует после того, как он становится узлом волокна.У компонента функции нет состояния, поэтому узел волокна также не имеет его.
Не будет ли достаточно добавить состояние к узлу волокна функционального компонента?
Поэтому React добавил свойство memorizedState в узел волокна функционального компонента для хранения данных, а затем использовал данные в функциональном компоненте через API, эти API называются хуками API.
Поскольку используются данные на оптоволоконном узле, API называется useXxx.
У каждого API хуков должно быть свое место для хранения данных, как это организовать? Есть две схемы, одна карта, а другая массив.
Если вы используете карту, вам нужно указать ключ в хуках api и получить доступ к данным в узле волокна в соответствии с ключом.
Если вы используете массив, порядок не может быть изменен, поэтому хуки API не могут появляться в логических блоках, таких как if, только на верхнем уровне.
Чтобы упростить использование, хуки в конечном итоге используют подход массива. Конечно, в реализации используется связанный список.
Каждый API-интерфейс хуков берет данные из соответствующего fiber.memoriedState для использования.
Хуки API можно разделить на 3 категории:
Первый класс — это класс данных:
- useState: хранить данные в соответствующем элементе fiber.memoriedState.
- useMemo: хранить данные в соответствующем элементе fiber.memoriedState, значение является результатом вычисления кэшированной функции и пересчитывать значение после изменения состояния.
- useCallback: сохраняет данные в соответствующем элементе fiber.memoriedState, значение — это функция, и функция повторно выполняется после изменения состояния, что представляет собой упрощенный API-интерфейс useMemo в сценарии, где значение — это функция, например. , useCallback(fn, [a,b]) эквивалентно useMemo(() => fn, [a, b])
- useReducer: хранить данные в соответствующем элементе fiber.memoriedState, значение — это результат, возвращаемый редюсером, а изменение значения может быть вызвано действием.
- useRef: Хранить данные в соответствующем элементе fiber.memoriedState, значение имеет вид {текущее: конкретное значение}, потому что объект остается неизменным, но текущее свойство изменилось, поэтому оно не будет изменено.
useState — самый простой способ хранения значений, useMemo — выполнение функций на основе состояния и кеширование результатов, что эквивалентно геттеру vue, useCallback — упрощение для случая, когда значение является функцией, а useReducer — запуск модификации. ценности через действие. useRef оборачивает слой объектов, и каждое сравнение одинаково, поэтому вы можете поместить некоторые неизмененные данные.
Независимо от формы, функция API этих хуков состоит в том, чтобы возвращать значение.
Вторая категория логична:
- useEffect: функция асинхронного выполнения будет выполняться снова при изменении зависимого состояния, а возвращаемая функция очистки будет вызываться при уничтожении компонента.
- useLayoutEffect: выполнить функцию синхронно после завершения рендеринга, вы можете получить dom
Оба этих хука api используются для выполнения логики, а логику, которой не нужно ждать рендеринга, можно поместить в useEffect.
Третья категория посвящена пересылке рефов:
Данные могут быть разделены по различным схемам, но элемент dom должен быть перенаправлен через ref.Так называемая переадресация ref заключается в создании ref в родительском компоненте, а затем дочерний компонент передает элемент. Если вы хотите внести некоторые изменения перед его передачей, вы можете использовать useImperativeHandle для его изменения.
Благодаря этим 3 типам API-интерфейсов и другим API-интерфейсам, которые будут добавлены позже, функциональные компоненты также могут выполнять хранение состояния, а также могут выполнять часть логики на некоторых этапах, что является решением, которое может заменить компоненты класса.
И что более важно, API-интерфейсы хуков представлены в виде вызова функции, которая передает параметры, а API-интерфейсы хуков могут быть дополнительно инкапсулированы в более мощную функцию, то есть в пользовательские хуки. Таким образом, можно реализовать повторное использование логики между компонентами.
Давайте вернемся к проблеме слишком глубокой вложенности компонентов класса и слишком больших компонентов для решения в начале, которую можно решить с помощью хуков:
- Расширение логики не требует вложенных hoc, просто вызовите еще один пользовательский хук
- Логику компонента не нужно писать в классе, ее можно полностью разделить на разные хуки
React решает проблему логического повторного использования компонентов класса через хуки API функциональных компонентов. (файбер предназначен для решения проблем с производительностью, а хуки — для решения проблемы повторного использования логики)
В vue2 логика переиспользуется через mixin, а также есть проблемы со слишком большим количеством компонентов, которые можно решить и в vue3 за счет схожих идей.
Чтобы опыт был ближе к оригиналу, теперь в основном все одностраничные приложения, которые не обновляют страницу, являются решениями браузерного рендеринга (csr), которые извлекают данные с сервера, а затем вносят изменения в dom. Но для некоторых недорогих машин по-прежнему требуется решение для рендеринга на стороне сервера (ssr). Но мы не можем вернуться к рендерингу шаблонизатора на стороне сервера в эпоху jsp и php, вместо этого нам нужно отрендерить его в строку на основе того же дерева компонентов. И рендеринг на стороне сервера, и рендеринг в браузере используют один и тот же код компонентов, что является изоморфным решением.
От появления технологии до улучшения окружающей экологии, это цикл.От первоначального рендеринга на стороне сервера до более позднего рендеринга на стороне клиента, затем появляется схема компонентов логического слоя и, наконец, на основе схема компонентов, рендеринг на стороне сервера должен быть реализован заново. Фактически, физический уровень не изменился, но логический уровень постоянно добавляется слой за слоем, цель состоит в том, чтобы повысить эффективность производства, снизить затраты на разработку и обеспечить качество, что также является тенденцией развития технологий.