Отслеживание является неотъемлемой частью разработки продукта для веб-сайтов, мобильных приложений или любого программного обеспечения, над которым вы можете работать. Очень важно понимать ваших пользователей, чтобы знать направления развития вашего бизнеса. В этой статье я собираюсь рассмотреть несколько вариантов реализации отслеживания с использованием JavaScript.
Если вы не знаете, что такое поведенческое отслеживание (behavioral tracking ), или вы не внедрили отслеживание в свои проекты, я приведу краткое объяснение:
Поведенческое отслеживание — это способ, которым компании получают информацию о значимых событиях, которые произошли в их платформе / приложениях; это особенно полезно для понимания поведения пользователей и выявления потенциальных недостатков и возможностей на конкретных страницах.
Как вы могли заметить в приведенном выше упрощенном определении, все это связано с получением ценной информации от событий, то есть от кликов по «призыву к действию», входов пользователей в систему и т.д. … Что бы это реализовать разработчики, должны определить техническую реализацию, которая позволяет им создать эффективный и масштабируемый способ отслеживания, но, как вы скоро поймете, отслеживание сопряжено с некоторыми техническими проблемами.
Как правило, самый распространенный способ это создание отдельных модулей, предназначенные для отслеживания, эти модули представляют собой просто инкапсулированные функциональные возможности, которые позволяют отправлять информацию в конечную точку, которая хранит полезную нагрузку, полученную от пользователей, на основе определенных типов событий.
Ниже простая реализация того, как может выглядеть модуль отслеживания:
class Tracker { static get ENDPOINT_URL() { return "my.endpoint.domain/tracking" } async track(payload) { const response = await fetch( Tracker.ENDPOINT_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload) } ); return response; } ... }
Как вы можете видеть выше, мы просто создаем класс, который содержит метод, который позволяет нам отправлять информацию в конечную точку; этот пример слишком прост, но этого достаточно для целей данной статьи, в реальном сценарии у вас будет/должна быть модель, которая проверяет параметры, которые вы хотите отслеживать, и тип данных, отправляемых в качестве полезной нагрузки.
Для этой статьи мы начнем с того, что в качестве цели будем отслеживать кнопку подписки, чтобы мы могли понять, сколько пользователей задействуют ее.
<button class="js-tracked-click subscription-button"> Subscription Button 1 </button>
Давайте посмотрим, как мы можем применять различные шаблоны для отслеживания одного и того же элемента.
Этот вариант заключается в импорте модуля отслеживания в модули вашего приложения и внедрения функции отслеживания в части логики соответствующего блока кода. Реализация этого шаблона будет выглядеть примерно так:
import Tracker from './Tracker'; class SubscriptionButton { constructor() { this._buttonHandler(); } _onButtonClick() { console.log('Click handler function'); Tracker.track({ type: 'click', element: 'Subscription_button_1' }); } _buttonHandler() { const button = document.querySelector('.js-tracked-click'); button.addEventListener('click', this._onButtonClick.bind(this)); } ... }
Это очень простой и функциональный подход, он широко используется, и у него есть несколько достоинств и недостатков, давайте проанализируем их:
Расширение исходного класса — еще один подход, целью которого является изоляция отслеживаемых элементов от функциональности исходного сценария. Идея состоит в том, чтобы расширить код для создания дополнительного слоя, предназначенного для отслеживания событий, давайте рассмотрим пример:
Мы реализуем функциональность скрипта:
class SubscriptionButton { constructor() { this._buttonHandler(); } _buttonHandler() { this._button = document.querySelector('.js-tracked-click'); this._button.addEventListener('click', this.onButtonClick.bind(this)); } _onButtonClick() { this.elementHasClass = e.currentTarget.classList.contains('subscription-button'); if (this.elementHasClass) { console.log('Click handler function'); } } ... }
Затем мы реализуем отслеживание:
import Tracker from './Tracker'; class TrackedSubscriptionButton extends SubscriptionButton { constructor() { super(); this._trackedMethods(); } _trackedMethods() { this._onButtonClickTracking(); this._anotherTrackedElement(); } _onButtonClickTracking() { if (super.elementHasClass) { super._button.addEventListener( 'click', () => Tracker.track({ type: 'click', element: 'Subscription_button_1' }); ); } } _anotherTrackedElement() { ... } }
Обратите внимание, как мы можем изолировать код, связанный с отслеживанием, в другом классе, важно, чтобы вы понимали, что мы должны быть осторожны, чтобы не дублировать логику для элемента, который вы хотите отслеживать, убедиться, что есть логика отслеживается и она может использоваться повторно Исходный класс, что в вышеприведенном случае мы используем нового слушателя события addEventListener и условие, но условие фактически совпадает с классом родителя, мы просто повторно используем свойство, которое его определяет. Этот подход не должен быть реализован с наследованием; если вы хотите вместо этого написать функциональный и декларативный код, вы можете использовать функцию более высокого порядка, которая оборачивает функцию отслеживания.
Другой способ отслеживать — это создать настраиваемую центрированную систему отслеживания, этот очень популярный шаблон, и я видел, что он используется в нескольких компаниях, обычно он состоит из отслеживания взаимодействий на основе свойств набора данных, например, скажем, вы хотите отслеживать клик по элементу:
Элементы для отслеживания:
<button data-click-tracking="subscription_button_left"> Subscribe </button> <button data-click-tracking="subscription_button_right"> Subscribe </button>
Единая функциональность трекера кликов:
import Tracker from './Tracker'; class ClickTracker { constructor() { this._bindClicks(); } static get TRACKED_ATTRIBUTE() { return 'data-click-tracking'; } static get TRACKED_ELEMENTS() { return document.querySelectorAll(`[${ClickTracker.TRACKED_ATTRIBUTE}]`); } _onClickHandler(event) { const element = event.currentTarget.getAttribute(ClickTracker.TRACKED_ATTRIBUTE); Tracker.track({ type: 'click', element })); } _bindClicks() { ClickTracker.TRACKED_ELEMENTS.forEach(element => { element.addEventListener('click', this._onClickHandler.bind(this)); }); } }
Таким образом, все отслеживаемые клики проходят через обработчик кликов, и мы можем идентифицировать их, используя пользовательский идентификатор, передаваемый через свойство набора данных. Отличным примером компаний, использующих этот подход, является менеджер тегов Google в google tag manager, где вы можете определить собственные классы или свойства данных, которые будут отслеживаться, и отправлять информацию в Google Analytics. Я считаю, что этот подход является лучшим из упомянутых до сих пор, поскольку вы можете применять этот же шаблон для других типов событий, таких как события прокрутки, он не ограничивается только кликами.
Как правило, вам необходимо отслеживать отправку формы или событие входа в систему, по многим причинам неэффективно добавлять отслеживание к кнопке, которая передает информацию (вход в систему может быть неудачным или запрос формы может вернуть ошибку).
Для этого вы можете использовать подход с использованием модуля отслеживания, добавив функцию отслеживания к ответу 200. Это было бы простой и хорошей идеей, но мы должны были бы создать много условий для каждого запроса, который необходимо отслеживать.
Допустим, у вас есть централизованный HTTP-клиент, который вы используете для всех асинхронных запросов (что почти всегда будет так); этот клиент возвращает promise, чтобы вы могли выполнить некоторый код для каждого модуля, а затем мы получили некоторые требования к отслеживанию, как указано ниже.
Допустим на нужно отслеживать следующие события, чтобы получить значимую информацию о наших пользователях и узнать, как мы можем улучшить их работу на платформе:
Итак, мы понимаем, что «призыв к действию» можно легко отследить с помощью события отслеживания кликов, но как насчет других? Все это разные события, использующие разные URL и требующие отслеживания разных данных, поэтому если мы используем централизованный HTTP-клиент, это будет выглядеть примерно так:
function HTTPPost(url = '', data = {}) { return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, cache: 'no-cache', redirect: 'follow', referrer: 'no-referrer', body: JSON.stringify(data), }) .then(response => response.json()); } export default HTTPPost;
и тогда мы сможем использовать его для отслеживания таких данных, как:
import HTTPPost from './http-client'; HTTPPost('/api/login', {userId, password, source: 'modal' }) .then(response => { Tracker.track({ type: 'successful-login', ...response }) } .catch(error => console.error(error))
Приведенный выше подход на самом деле не является плохим, но нам придется каждый раз импортировать модуль Tracker в каждый файл, который будет выполнять асинхронный запрос.
Это будет последний подход, который мы рассмотрим в этой статье, и он мне действительно нравится. Основы этого подхода основаны на добавлении функции отслеживания один раз в метод HTTPPost, после чего мы можем использовать словарь, который будет содержать URL-адреса, которые мы хотим отслеживать, и они будут сопоставлены с моделью свойств, где каждый URL-адрес должен отслеживаться.
В основном мы берем код из предыдущего подхода и добавляем отслеживание ответа на promises:
import Tracker from './Tracker'; function HTTPPost(url = '', data = {}) { return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, cache: 'no-cache', redirect: 'follow', referrer: 'no-referrer', body: JSON.stringify(data), }) .then(response => response.json()) .then(response => Tracker.request(url, response));} export default HTTPPost;
Как вы видите, мы выполняем Tracker.request для всех запросов, теперь мы должны определить, какие запросы мы на самом деле хотим отслеживать и какие параметры релевантны для отслеживания этих запросов, поэтому мы можем использовать словарь, подобный этому:
const TRACKED_URLS = { '/api/login': ['userId', 'source', 'url', 'type'], '/api/logout': ['userId', 'time', 'type'], 'api/subscription': ['userId', 'source', 'type'], ... }; export default TRACKED_URLS;
В приведенном выше примере мы используем список для хранения отслеживаемых свойств. После этого метод отслеживания запросов может быть добавлен в модуль отслеживания. Мы можем сделать что-то вроде этого:
import TRACKED_URLS from './tracked-urls'; class Tracker { static get ENDPOINT_URL() { return "my.endpoint.domain/tracking" } async track(payload) { const response = await fetch( Tracker.ENDPOINT_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload) } ); return response; } request(url, data) { const URL_PROPERTIES = TRACKED_URLS[url]; const PAYLOAD_PROPERTIES = Object.keys(data); const arePropertiesValid = URL_PROPERTIES && URL_PROPERTIES.every(property => ( PAYLOAD_PROPERTIES.includes(property) )); if (!arePropertiesValid) return false; this.track(data); } }
Метод request проверяет, что все отслеживаемые элементы имеют правильные переданные свойства, он служит в качестве централизованного фильтра и словаря отслеживания централизованного запроса. Этот подход прост и очень хорошо масштабируется, потому что у вас есть все отслеживаемые URL-адреса в одном месте, которое позволяет быстро добавлять и удалять их по требованию.
Как было указано в начале, цель этой статьи — показать хорошие и плохие стороны каждой реализации отслеживания, чтобы вы могли решить, какая из них лучше для вас и вашей команды.
На данный момент это все, я надеюсь, что вам понравилось это статья — если это так, помните, что вы можете поделиться им со своими друзьями или оставить комментарий в Reddit или Twitter, нажав на социальные ссылки (в оригинальной статье).
Оригинальная статья Enmanuel Durán — Efficient behavioral tracking in javascript applications
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…