Еще в 2018 году Google объявил, что скорость загрузки будет важным фактором для Google Search и Google Ads. Это вызвало большой разговор среди маркетологов о производительности. Производительность всегда была важна, особенно в контексте электронной коммерции, но она стала актуальной проблемой, когда Google поднял ставки.

Поскольку такие компании, как Google и Facebook, установили стандарты мгновенной и бесперебойной работы приложений и веб-сайтов, скорость загрузки стала одним из наиболее важных факторов любого интернет-опыта. Если время загрузки превышает 2 секунды, пользователи просто не будут оставаться на вашей странице достаточно долго.

Производительность сайта может страдать по разным причинам, но проблемы часто связаны с JavaScript, который маркетинговые команды хотят запускать на сайте. Каждый неоптимизированный JavaScript SDK, от рекламных пикселей до трекеров и встроенных CRM, используется отделом маркетинга для получения дополнительных данных.

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

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

В этом посте рассказывается, как RudderStack работал с нашим клиентом Loveholidays над разработкой высокопроизводительного JavaScript SDK, который сократил время выполнения с 200–300 мс до 20–60 мс. Если вы предпочитаете смотреть наш вебинар по запросу на эту тему, вы можете смотреть его здесь.

Эта проблема

Одним из основных факторов, влияющих на производительность веб-страницы, являются используемые сторонние библиотеки. Есть два способа замедлить загрузку этих библиотек:

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

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

Скорость сайта и SDK RudderStack JavaScript

С такими продуктами, как RudderStack, все еще сложнее. Вот две основные сложности, связанные с производительностью:

Целевая интеграция влияет на размер библиотеки

SDK RudderStack JavaScript действует как промежуточное программное обеспечение между веб-сайтом нашего клиента и множеством различных мест, куда они отправляют данные. Целевые потребности зависят от клиента, поэтому окончательный размер библиотеки может значительно измениться.

Варианты пользовательских полезных данных JSON

Еще одна причина дополнительных сложностей с производительностью — полезная нагрузка, которую должен доставлять RudderStack Javascript SDK.

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

На пути к решению

Из-за двух вышеперечисленных условий очень сложно обеспечить единообразие использования всех библиотек или соображений производительности до того, как SDK будет развернут в рабочей среде.

Некоторое время мы работали над улучшением производительности нашего JavaScript SDK, особенно потому, что мы обслуживаем несколько корпоративных компаний электронной коммерции, но нам выпала честь работать с Дэвидом Аннезом в Loveholidays над завершением и тестированием высокопроизводительной библиотеки.

Вот как мы это сделали.

Повышение производительности JavaScript SDK

Две проблемы, о которых мы упоминали ранее, требуют разных тактик для повышения скорости. Мы начнем с объяснения того, что мы сделали для обработки произвольного размера используемой библиотеки.

Уменьшение размера библиотеки

Сам по себе начальный размер пакета SDK для JavaScript невелик. Проблемы начинаются, когда необходимо поддерживать собственные направления.

Собственный пункт назначения — это любой пункт назначения, в который данные передаются напрямую, вместо того, чтобы отправлять данные в плоскость данных RudderStack и направлять их в приложение. Например, многие наши клиенты запускают SDK Google Analytics, Hotjar и Firebase изначально через SDK RudderStack JavaScript. Одной из основных причин этого является производительность, но бывают случаи, когда пункт назначения не предлагает общедоступный API. В любом случае это необходимость.

Загрузка нативных библиотек неизбежно увеличивает задержку; однако основная проблема заключается в том, что по мере того, как мы поддерживаем больше таких библиотек, в SDK RudderStack JavaScript добавляется больше инструментов, и его размер увеличивается.

Решение: загружайте только то, что вам нужно

Высокоуровневое решение здесь было довольно простым, во многом благодаря хорошим размышлениям Дэвида и его команды.

На базовом уровне высокопроизводительный пакет SDK для JavaScript не включает инструментальный код для конечных пунктов назначения в основной пакет SDK. Вместо этого SDK извлекает только параметры конфигурации назначения из панели управления RudderStack (например, идентификатор дорожки, ключ API, секрет и т. д.), используя метод requireIntegration_.

Давайте рассмотрим быстрый пример, чтобы увидеть, как это работает на практике.

Как только JavaScript SDK получает такой вызов, как rudderanalytics.requireIntegration("GA"), он автоматически извлекает инструментальный код Google Analytics (например, GAPlugin.js), который обрабатывает логику преобразования и сопоставления для полезной нагрузки события RudderStack. Это включает в себя тип вызова и вызовы API.

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

С помощью этой стратегии достигается следующее:

  • Любые нативные библиотеки извлекаются клиенту только тогда, когда они требуются (или, другими словами, только если происходит вызов, требующий библиотеки).
  • Одновременно все последующие вызовы ставятся в очередь, поэтому на клиенте нет блокировки и, следовательно, нет дополнительного снижения производительности.
  • Эта стратегия позволяет библиотеке JavaScript поддерживать минимальный размер и гарантировать, что потеря скорости при первой загрузке страницы будет минимально возможной.

Благодаря реализации вышеизложенного и удалению ненужных фрагментов интеграции время загрузки Loveholidays сократилось почти в 10 раз по сравнению с их предыдущим решением (analytics.js от Segment).

В контролируемых тестах время загрузки составляло 20–60 мс, а не 200–300 мс.

XHR против sendBeacon или Sync против Async

Чтобы еще больше повысить производительность нашего SDK, мы решили поэкспериментировать с sendBeacon.

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

Однако наиболее важным аспектом является асинхронный характер Beacon. Мы предположили, что с помощью sendBeacon мы можем еще больше уменьшить задержку ввода.

Подробности: Beacon против XHR

Выполнение синхронных вызовов XHR для отслеживания может повлиять на первую задержку ввода (FID) страницы, замедляя реакцию при измерении такими инструментами, как маяк.

Вместе с Дэвидом и командой Loveholidays мы провели A/B-тестирование Beacon и XHR для RudderSTack SDK. Спойлер: это сработало. Мы увидели, что среднее значение FID упало с 200 до 20 мс при использовании Beacon. Большая часть причин для этого была разгружена на пакетные + асинхронные вызовы, поддерживаемые новым SDK RudderStack.

Это реальная диаграмма из теста Loveholidays:

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

Заключение

Наша миссия в RudderStack — построить максимально производительные конвейеры данных о клиентах. Мы понимаем, что все, что мы делаем с нашими SDK, повлияет на опыт конечного пользователя, и по этой причине мы очень серьезно относимся к производительности.

Вышеупомянутые изменения, которые мы внесли в наш Javascript SDK, позволили нам сократить время выполнения SDK с 200+ мс до 20–60 мс, что является не только огромным улучшением, но и стандартом по сравнению с другими поставщиками в этой области.

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

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

Зарегистрируйтесь бесплатно и начните отправлять данные

Протестируйте наши конвейеры потока событий, ELT и обратного ETL. Используйте наш источник HTTP для отправки данных менее чем за 5 минут или установите один из наших 12 SDK на свой веб-сайт или в приложение. "Начать".

Первоначально этот блог был опубликован по адресу:
https://rudderstack.com/blog/javascript-sdk-from-200ms-to-20ms

Дополнительные материалы на plainenglish.io