Членская программа JD PLUS является первой платной членской программой электронной коммерции в Китае, и количество официально открытых членов превысило 10 миллионов. Моя команда взяла на себя разработку интерфейса этого проекта в 2016 году, наблюдала за его быстрым ростом и внесла в него свой вклад.
Этот проект имеет несколько особенностей:
Во-первых, большой спрос. Мобильный терминал разработан с использованием H5.Некоторые люди спрашивали, почему бы не использовать нативную или RN разработку?Я думаю, судя по количеству требований и скорости итерации этого проекта, даже H5 трудно держать, так что не ждите нативной и РН.
Во-вторых, есть много продакт-менеджеров. Общий проект связан с одним или двумя продакт-менеджерами, для этого проекта нам нужно подключиться к "команде" продакт-менеджеров в другом месте, общие проекты заменяются продакт-менеджерами один за другим, а этот проект заменяется партиями ... Мы уже отправили нескольких менеджеров по продуктам для членов PLUS. R & D железа и менеджер по продукции проточной воды.
Таким образом, членская программа PLUS — это бизнес-сторона, менеджер проекта и менеджер по продукту, но, в конце концов, это наши исследования и разработки. Каждый раз, когда я думаю об этом, старая песня Е Цяньвэнь всегда будет звучать в моих ушах: «Мир длинный, прохожие спешат, приливы и отливы…».
Книга пришла в норму. При большом количестве пользователей и частых повторениях потребностей обеспечение онлайн-безопасности и стабильности всегда является главным приоритетом. Поэтому мы всегда были осторожны в плане корректировки архитектуры и оптимизации производительности, уделяя особое внимание некоторым мелким исправлениям и мелким исправлениям, и только когда будут внесены масштабные изменения, произойдут крупные обновления. Однако наши размышления и практика по этим вопросам никогда не прекращались, мы проверили несколько эффективных схем оптимизации, которые будут применены в следующей волне доработок.
Хотя я не полностью согласен с утверждением, что «сложность фронтенд-разработки удваивается каждые 18 месяцев», неоспоримым фактом является то, что это направление разработки имеет высокую скорость итерации. Если подождать, пока все эти схемы оптимизации будут применены, а потом говорить об этом, то может быть не так уж и свежо. Поэтому я решил сначала поделиться этими планами, обсудить с заинтересованными друзьями и дальше их улучшать.
Эти решения в основном нацелены на мобильный терминал, а основное направление оптимизации — повысить скорость загрузки домашней страницы, особенно скорость загрузки первого экрана и слабую сетевую среду. Начиная с постоянного кэширования, сокращения объема кода, оптимизации запросов к интерфейсу и улучшения субъективного восприятия, приложение больше всего меняет.PWA
и обновить архитектуру.PWA
Офлайн-кеширование может сильно улучшить пользовательский опыт, но на первую скорость загрузки оно не влияет, приходится полагаться на другие методы оптимизации, это комбинация ударов. Начнем с обновления архитектуры.
1. Обновление архитектуры
Проект планирует перейти наGaea4.0
Scaffolding [1], это набор общих шаблонов одностраничных приложений Vue, разработанный нашей командой на основе webpack 4. Предыдущие серии версий были проверены десятками проектов и относительно стабильны. Недавно выпущенная версия 4.0 имеет множество улучшений по сравнению с предыдущей версией.
-
вебпак обновлен до 4.0
-
Бабель обновлен до 7.0
-
Vue-loader обновлен до версии 15.
-
Переработан плагин загрузки, загрузка в один клик на тестовый сервер стала быстрее и стабильнее.
-
Чтобы решить проблему, связанную с тем, что мобильный телефон и компьютер на нашем заводе не могут получить доступ друг к другу в разных локальных сетях, было интегрировано разработанное нами решение Carefree [2], которое удобно для тестирования и отладки реальных машин.
-
Интегрированная библиотека компонентов Nutui [3], может загрузить необходимые компоненты пользовательского интерфейса по требованию
-
Он интегрирует самостоятельно разработанный инструмент SMOCK для имитации данных на основе swagger [4].
-
Поддержка автоматического создания каркасного экрана [5]
-
Поддержка PWA
-
…
Миграция преследует несколько основных целей:
Во-первых, инструмент построения веб-пакетов, реализующий этот проект, обновлен до версии 4.0.Ранее он разрабатывался на основе веб-пакета 2.0.В веб-пакете 4 есть много улучшений, таких как:
-
Scope Hoisting (улучшение области действия, добавленное webpack3), которое ускоряет выполнение JS за счет уменьшения количества функций закрытия.
-
Размер производственной сборки меньше
-
Среда разработки повышает скорость сборки за счет оптимизированного механизма инкрементной сборки, предоставляя подробные сведения об ошибках и подсказки.
Второй,Gaea4.0
Babel — это версия 7.0, основанная на Babel7, более умный полифилл Babel может быть загружен по запросу.
Еще раз, PWA, скелетный экран и другие решения, опробованные в этом плане оптимизации,Gaea4.0
Доступна базовая поддержка.
наконец,Gaea4.0
Интегрированная программа Carefree, новые подключаемые модули загрузки и другие функции облегчат дальнейшую разработку и отладку реальных машин.
2. Загрузка полифилла Babel по требованию
Сегодняшняя разработка веб-приложений создается локально, поэтому компиляция JS-кода высокой версии в синтаксис низкой версии на этапе сборки является условием, что не только использует новый синтаксис, но также решает проблему совместимости браузеров низкой версии. Самый известный инструмент для такого преобразования — Babel. И Babel долгое время подвергался критике, и это проблема полифилла.
Babel по умолчанию преобразует только синтаксис JavaScript, а не новые API, такие как глобальные объекты, такие как Promise, Generator, Set, Maps, Symbol и т. д. Некоторые методы, определенные для глобальных объектов (например, Object.assign), не будут перекодированы. Если вы хотите, чтобы неперекодированный API правильно работал в среде более ранней версии, вам необходимо использовать полифилл.
Существует множество вариантов полифиллов, каждый со своими проблемами. В настоящее время схема babel-polyfill обычно используется в приложениях, тогда как схемы babel-runtime и babel-plugin-transform-runtime обычно используются в сторонних библиотеках.
babel-polyfill предоставляет полную оболочку среды, включая модули с пониженной версией для всех API, и может предоставить итоговую информацию для новых API и методов для глобальных объектов.Основной недостаток заключается в том, что файл большой, около 80–90 КБ после сжатия. Эта схема в настоящее время используется в проекте, и на этот раз она считается оптимизированной для уменьшения размера загружаемого кода.
Как упоминалось выше, эта волна реконструкции переместит проекты вGaea4.0
В строительных лесах Babel новых строительных лесов обновлен до последней версии 7.0. Babel 7 — это большая версия похожего на скалу обновления, выпущенного почти через три года после запуска Babel 6. Он содержит много новых функций, одна из интересных — поддержка более интеллектуальной загрузки полифилов по запросу.
Babel7 в основном предоставляется через@babel/preset-env
Реализовать загрузку по требованию.
использовать@babel/preset-env
тоже нужно сначала установить@babel/polyfill
, но окончательный пакет не будет импортировать все полифиллы.
npm install @babel/polyfill --save
В то же время вам необходимо указать диапазон браузеров, которые должны быть совместимы, в поле target файла .browserslistrc или .babelrc.
Затем в файле .babelrc@babel/preset-env
настроить.
@babel/preset-env
Параметры, связанные с загрузкой полифиллов по требованию,useBuiltIns
, у которого есть два значения, на которые следует обратить внимание:entry
а такжеusage
.
когда значениеentry
, Вавилон будетimport"@babel/polyfill"
илиrequire("@babel/polyfill")
Операторы заменяются одним требованием полифилла на основе указанной нами конфигурации среды.
как будет
import "@babel/polyfill";
заменить
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
когда значениеusage
более умный. Babel добавит определенные полифиллы в соответствии с потребностями каждого файла и указанной конфигурацией среды.Более того, один и тот же полифилл в пакете будет загружен только один раз, что также помогает уменьшить размер пакета. Предполагается, что Babel достигает этой точной функции полифилла по требованию посредством статического анализа файла.
Такие как
var a = new Promise();
После преобразования (если указанная среда его не поддерживает)
import "core-js/modules/es6.promise";
var a = new Promise();
После преобразования (если поддерживается указанной средой)
var a = new Promise();
Мы попробовали, сначала укажите диапазон браузеров, которые должны быть совместимы, а затем установите@babel/polyfill
и воля@babel/preset-env
изuseBuiltIns
Значение параметра установлено наusage
. Таким образом, Babel автоматически проанализирует каждый файл и загрузит полифилл, необходимый для каждого файла, принимая во внимание указанный нами диапазон совместимости браузера. В окончательный проект были введены только некоторые полифиллы.После расчета упакованный код (мин.) более непосредственно импортируется и завершается.
Решение babel-polyfill меньше более чем на 60 КБ, а также позволяет избежать загрязнения глобальных переменных.
Включите режим отладки в конфигурации Babel, и вы увидите, какие полифиллы добавляются в каждый файл при сборке:
(Кто-то из Zhihu спросил: «Какой это возраст, и он все еще совместим с Android
4.0 и iOS 8.0? "Я вздохнул, пожал плечами и пожал руку бару...)
Дальнейшие мысли по этому вопросу:
Этот способ загрузки полифиллов гораздо более совершенен, чем традиционный, но все же не идеален: например, полифилл, который нужно вводить в соответствии с указанным нами диапазоном браузеров, может быть избыточным для браузеров более высоких версий.
Я лично считаю, что идеальное решение — сначала определить область API, которым могут понадобиться полифиллы, посредством статического анализа на этапе компиляции, но не упаковывать полифиллы в него, вместо этого, когда пользователь обращается к странице в браузере, JS используется встроенный в страницу скрипт.Поочередно проверьте, поддерживает ли текущий браузер эти новые API, найдите неподдерживаемые и загрузите соответствующий файл полифилла на сервер через запрос. Конечно, для этого требуется что-то вродеpolyfill.io
Поддержка схемы полифилла на стороне сервера для . Мы продолжим исследования в этом направлении в будущем.
3. Постоянный кэш
PWA
Это очень жарко, это бесполезно в текущем проектеPWA
Я стесняюсь здороваться с людьми, когда выхожу из дома.PWA
Среди ряда функций наиболее важным неавтономным кешем является не что иное, как офлайн-кеш.Хотя до H5 есть API-интерфейс оффлайн-кэша (кеша приложений), жаль, что он не прост в использовании.PWA
Автономного кэширования достаточно, чтобы забить его насмерть в песок.
С точки зрения бизнеса, мы не думаем, что этот проект подходит для автономного доступа, но мы можем воспользоватьсяPWA
Кешируйте статические ресурсы в автономном режиме, чтобы повысить скорость доступа к странице.
В этом сценарии используйтеServiceWorker
Данные HTML и интерфейса самой страницы не кэшируются, кэшируются только статические ресурсы, и кэш используется преимущественно. В случае не первого доступа статические ресурсы будут кэшироваться, и скорость доступа к странице может быть значительно улучшена.
Но есть проблема, то есть проблема обновления страницы. Использование стратегии cache-first означает, что каждый раз, когда вы заходите на страницу, кеш используется напрямую, когда есть кеш. Если кеш обновляется, страницу необходимо обновить после обновления кеша, чтобы увидеть изменения. Автоматическое обновление страницы серьезно влияет на взаимодействие с пользователем, а запрос пользователя на обновление вручную выглядит немного странно в приложении, и не все пользователи будут обновлять вручную. Для участников PLUS, которым необходимо стоять в очереди и часто обновлять информацию, пользователи могут почувствовать большее влияние. У API офлайн-кеша HTML5 тоже есть эта проблема, которая, конечно, не является дефектом, а определяется стратегией «предпочтительного использования кеша», но не в полной мере отвечает нашим потребностям.
В ответ на эту проблему наше решение состоит в том, чтобы изменить номер кэшированной версии и номер версии в URL-адресе, ссылающемся на файл на странице, когда файл обновляется, чтобы браузер мог напрямую использовать новый файл без использования кеша. После загрузки страницы кеш тоже обновится, и при следующем посещении будет использоваться кеш.
В этой схеме еще есть место для оптимизации, только те файлы, которые изменились, должны изменить номер версии в URL и использовать новый файл, в то время как другие статические ресурсы на странице, которые не изменились, могут и должны продолжать использовать кеш. . Согласно этой идее, мы должны как можно больше извлекать из кода стабильные и нечасто меняющиеся модули (такие как Vue и его плагины), чтобы эту часть контента можно было максимально кэшировать, и, конечно же, это может быть обновлен таким же образом, когда это необходимо. Части, которые часто изменяются (например, бизнес-код), должны быть упакованы независимо, и чем меньше объем, тем лучше, чтобы уменьшить накладные расходы на обновления страниц и кэша.
Для извлечения этих стабильных общедоступных модулей мы используем встроенный веб-пакет.DllPlugin
а такжеDllReferencePlugin
Плагины для достижения, через эти два плагина, чтобы самостоятельно скомпилировать эти общие модули заранее, типа пакет vendor.dll.js, и тогда они не будут скомпилированы, если эта часть кода не будет изменена, поэтому проект обычно строит Скорость также сильно увеличится. Пакет vendor.dll.js существует независимо, и хеш не меняется, что особенно удобно для постоянного кэширования.
Поэтому, когда наш бизнес-код меняется, нам нужно только публиковать бизнес-пакет (App.js) с новым номером версии, а Vendor.dll.js по-прежнему использует локальный кэш.
Давайте посмотрим на конкретную ситуацию загрузки.
Первый визит, нетPWA
Кэш, все ресурсы выходят в интернет. После загрузки страницы PWA кэширует статические ресурсы.
Для последующих посещений статические ресурсы предпочтительно загружаются из кеша, что очень быстро.
Когда бизнес-код будет обновлен, измените номер версии в URL-адресе, который ссылается на файл app.js на странице, чтобы app.js не использовал кеш, а другие статические ресурсы, которые были кешированы, по-прежнему могли использовать кеш. . Также измените номер версии кеша, кеш тоже будет обновляться после загрузки страницы, и новый файл app.js тоже будет кешироваться.
При повторном доступе все статические ресурсы, включая app.js, по-прежнему кэшируются.
В-четвертых, оптимизация запросов
Это проект с разделением фронтенда и бэкенда, фронтенд представляет собой стандартный Vue SPA, который полностью взаимодействует с бэкендом через интерфейсы. Бизнес-логика членства в PLUS относительно сложна, включает множество пользовательских состояний, и логика страницы также сложна. Разные пользователи видят разные интерфейсы, на которые влияют различные факторы, такие как статус пользователя и фоновая конфигурация.
Некоторые интерфейсы взаимозависимы, например, есть интерфейсы, требующие передачи статуса пользователя, поэтому сначала необходимо получить статус пользователя через информационный интерфейс пользователя. Другим примером является интерфейс данных продукта. Сначала вам нужно запросить интерфейс информации о конфигурации этажей, определить, какие этажи находятся на текущей странице, а затем решить, какие этажи запрашивать данные.
Этот запрос последовательного интерфейса замедляет отрисовку первого экрана, что в настоящее время является серьезной проблемой, влияющей на производительность домашней страницы, и также находится в центре внимания этой оптимизации.
Рендеринг на стороне сервера (например, Vue SSR), первый экран — это, конечно, самое идеальное решение. Однако в настоящее время это кажется нереалистичным.Команда R&D этого проекта также относительно сложна.Фронтенд и бэкенд представляют собой две межрабочие и межведомственные команды с огромными требованиями и частой сменой страниц. Полное разделение передней и задней частей более полезно для четкого определения обязанностей, повышения эффективности и уменьшения споров.
Другим компромиссным решением является прямая ссылка на файл внутреннего шаблона на странице, и коллеги из отдела исследований и разработок используют этот файл шаблона для печати статуса пользователя, конфигурации этажа и другой предварительной информации на странице. в браузере Прочтите эту информацию напрямую, а затем запросите интерфейсы, которые полагаются на эти данные. Это позволяет избежать проблемы с последовательными запросами, а также сократить количество запросов, помогая ускорить загрузку и отрисовку страницы. Это оптимизация, мы планируем принять эту схему.
До оптимизации:
После оптимизации критические запросы значительно выдвигаются вперед:
До оптимизации:
После оптимизации страница начинает отображаться значительно раньше:
Есть еще мечты. Разделение фронтенда и бекенда — это улучшение, но полное разделение не идеально, например, будут проблемы со скоростью загрузки и SEO в верхней части страницы.前后端分离+服务端首屏渲染
Кажется, это лучшее решение. Оно сочетает в себе преимущества разделения интерфейса и сервера и рендеринга на стороне сервера. Оно не только обеспечивает разделение интерфейса и сервера, но и обеспечивает скорость рендеринга домашней страницы. , что также способствует SEO. Но сегодня, когда такие интерфейсные фреймворки, как Vue и React, популярны, рендеринг на стороне сервера уже не так прост, как HTML-страницы прошлого, даже если рендерится только первый экран. Изоморфизм внешнего и внутреннего интерфейса может быть лучшим решением, и в этом сценарии работа по рендерингу на стороне сервера, очевидно, больше подходит для внешнего интерфейса, поэтому используйте
Для Node.js необходимо иметь средний уровень.
5. Скелетный экран
С помощью ряда оптимизаций, в дополнение к объективному сокращению времени рендеринга первого экрана, мы также добавили на страницу экран-скелет, чтобы пользователь субъективно чувствовал, что скорость загрузки и рендеринга страницы выше реальной ситуации. Правда есть правда, а способ использования солдат тоже для пользовательского опыта.
Давайте сначала разберемся с концепцией каркасного экрана. Каркас экрана относится к общей структуре страницы, отображаемой пользователю до загрузки данных страницы, а затем для ее замены отображается реальное содержимое страницы. Это средство управления загрузкой, которое стало популярным в последние два года, и по сути является эффектом перехода во время процесса загрузки интерфейса.
Перед завершением загрузки заранее отображается общий контур веб-страницы, а затем постепенно загружается реальный контент, что может не только снять беспокойство пользователя в ожидании, но и сделать процесс загрузки интерфейса более заметным. естественный и гладкий, а также уменьшить долговременный белый экран или мерцание. Скелетный экран может дать людям ощущение, что содержимое страницы «отображено частично», и это лучше, чем традиционный эффект загрузки.
Наша команда провела углубленное исследование технологии каркасного экрана и разработала@nutui/draw-page-structure
Плагин веб-пакета из [4] может автоматически генерировать экран скелета страницы в виде чистого DOM через puppeteer и поддерживает автоматическую вставку на указанную страницу. Также позволяет настраивать и корректировать, если вы не удовлетворены автоматически сгенерированными результатами.
Мы использовали этот плагин, чтобы опробовать его в проекте, и эффект все еще хороший. Скелетный экранный код в чистой форме DOM содержит меньший объем данных, чем изображения и Canvas, и более гибок в настройке.
6. Формат изображения
Домашняя страница канала участника Plus — это типичная страница электронной коммерции, содержащая множество изображений. Использование новых форматов изображений может значительно уменьшить объем загружаемых изображений и помочь повысить скорость анализа и рендеринга изображений, тем самым повышая скорость рендеринга страниц. Для мобильного веба есть еще одно важное преимущество — экономия трафика пользователей (China Mobile — 30M5 юаней, ха-ха).
В прошлом году мы применили его в проектеWebP
Формат, работает хорошо. Например, для фонового изображения сжатый формат png имеет размер 35 КБ, а сжатый формат png — 35 КБ.WebP
Всего 4 КБ, разницы в качестве между ними практически нет.
Основным препятствием для принятия новых форматов изображений является совместимость.WebP
Например, браузеры Google и браузеры Oppen хорошо поддерживаются, а Firefox и Edge также обеспечивают поддержку в новой версии. К сожалению, Apple не приняла меры, и Safari до сих пор не поддерживает его. Если приложение хочет его поддерживать , ему нужно упаковать библиотеку парсинга самостоятельно (после тестирования выяснилось, что приложение JD.com для iOS уже предоставило поддержку, пожалуйста, поставьте лайк).
Мы используемWebP
Способ заключается в том, чтобы судить о том, поддерживает ли его текущий браузер через JS на странице.WebP
, если поддерживается, добавьте в тело класс с именем «webp» и запишите результат оценки в localStorage, а затем прочитайте его непосредственно из localStorage при входе на страницу, не выполняя код оценки каждый раз. Затем используйте селектор «.webp» в css страницы и определите, загружать или нет, оценивая результат в фильтре изображений Vue.WebP
форматировать изображение.
document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') === 0
Для этой оптимизации мы рассматриваем увеличениеDPG
Поддержка формата изображения.
DPG - это технология сжатия изображений, представленная инфраструктурным отделом нашей фабрики - отделом интеллектуального хранения.Изображения, сжатые DPG, совместимы с JPEG и поддерживаются всеми платформами и браузерами.DPG - технология сжатия с потерями, но через 5 пользователей 10000 Тест просмотра этого изображения человеческим глазом не отличается от сравнения резкости WebP. Эта технология может эффективно уменьшить размер изображения на 50 %, уменьшить трафик пропускной способности CDN на 50 % и повысить скорость рендеринга изображений пользователей на устройстве.
Исходя из моего личного понимания,DPG
Формат должен быть вторичным сжатием изображения формата JPEG через определенный алгоритм, который по существу является JPEG (хотя имя расширения было изменено), так что существует возможность так называемой «поддержки браузера на платформе». Следовательно, это особенно подходит для замены изображения в формате JPEG сDPG
Формат, разумеется, исходит из того, что на сервере естьDPG
форматировать изображение. Система изображений нашей фабрики автоматически создаст соответствующее изображение для загрузки.DPG
форматировать изображение. Итак, мы установилиDPG
Условием использования формата является то, что исходное изображение
jpeg, а изображение находится в системе изображений нашей фабрики. с учетом существующихWebP
Основываясь на логике загрузки изображения формата, наша логика загрузки отсортированного изображения показана на следующем рисунке:
Давайте сначала поговорим здесь, я пошел, чтобы принять участие в обзоре потребностей программы членства PLUS…
7. Расширенное чтение
[1] https://www.npmjs.com/package/gaea-cli
[2] http://carefree.jd.com
[3] http://nutui.jd.com
[4] http://smock.jd.com
[5] https://www.npmjs.com/package/@nutui/draw-page-structure