Конструкция без следов заглубленной точки

Архитектура
Конструкция без следов заглубленной точки

Эта статья была написана членом командыСяо ФанЕму разрешено исключительное использование Tuya Front-end, включая, помимо прочего, редактирование, пометку оригинальности и другие права.

Зачем вам нужна система захороненных точек?

в кино

Фронтенд-разработка siege lion счастливое кодирование, очень горжусь тем, что занимаюсь разработкой разделения бизнеса и пользовательского интерфейса, различные шаблоны проектирования, оптимизация алгоритмов по очереди, код написан идеально (код трудового капитала - первый в мире), без ошибок , программа идеальна, Совместимость №1, код может драться и сопротивляться высокому качеству. Легко зарегистрируйтесь после работы и идите домой, чтобы присмотреть за ребенком.

в реальности

На самом деле среда разработки — это не то же самое, что производственная среда, и каким бы совершенным ни был процесс тестирования, все равно будут пропущенные тесты. С учетом использования пользователемКлиентская среда, сетевая средаСуществует ряд неопределенных факторов.

Так что в процессе разработки надо помнить три принципа (я вру)

  1. Не бывает идеального кода, есть не обнаруженные ошибки
  2. Никогда не верьте тестовой среде, ни одна тестовая среда не охватывает все онлайн-ситуации
  3. Если нет отзывов в сети, не сомневайтесь, проблема должна быть спрятана глубоко-глубоко

Что такое система скрытых точек

Скрытая точка похожа на камеру в городе: с точки зрения продукта она может отслеживать поведение пользователей в наших продуктах, обеспечивая основу для итерации продукта и стабильности проекта.КТО, КОГДА, ГДЕ, КАК, ЧТО являются основными аспектами сбора данных.

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

Могилы можно условно разделить на три категории:

  1. Нет следов похороненных- Без разбора собирать всю информацию о странице, включая вход и выход на страницу, клики по событиям и т. д., для получения полезной информации требуется сброс данных.
  2. Визуализируйте закопанные точки- Получите определенные баллы в соответствии с созданной структурой страницы и проанализируйте баллы отдельно
  3. Вручную похороните бизнес-код- В соответствии с конкретным и сложным бизнесом удалите два вышеуказанных места, которые не могут быть покрыты, и похороните бизнес-код.
код похоронен Визуализируйте закопанные точки Нет следов похороненных
Типичная сцена Бесследные закопанные точки не могут быть покрыты, например, требуются бизнес-данные Простая и каноничная сцена страницы Простая и стандартизированная сцена страницы,
Преимущество Очистить бизнес-данные Стоимость разработки низкая, и операторы могут напрямую настраивать соответствующие закопанные точки. Настройка не требуется, данные можно отследить
недостаточный Данные невозможно отследить, а стоимость разработки высока. Бизнес-данные не могут быть связаны, и данные нельзя отследить Количество данных велико и не может быть связано с бизнес-данными

В большинстве случаев мы можем собрать все информационные данные через скрытую точку без следов, а затем сотрудничать с визуальной скрытой точкой, чтобы найти определенную точку, чтобы можно было соответствующим образом проанализировать большую часть информации о скрытой точке.

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

Скрытая разработка SDK

Сбор и анализ данных о захороненных точках

  • Основные данные события
    • время события
    • Моментальный снимок информации о странице, как это происходит
  • страница
    • Страница ПВ, УФ
    • Время пребывания на странице пользователя
    • событие перехода на страницу
    • Страница уходит в фон
    • Пользователь покидает страницу
  • Информация о пользователе
    • пользовательский идентификатор
    • Отпечаток пользовательского устройства
    • Информация об устройстве
    • ip
    • позиция
  • Поведение пользователя при работе
    • пользовательские клики
      • нажмите цель
  • AJAX-запрос страницы
    • запрос выполнен
    • Запрос не выполнен
    • Истекло время запроса
  • ошибка страницы
    • Ошибка загрузки ресурса
    • Ошибка запуска JS
  • Ресурс загружает новую производительность
  • картина
  • сценарий
  • скорость загрузки страницы

Указанные выше данные передаются через3 измерениядля определения скрытых событий

  • ·LEVEL: описывает уровень журнала скрытых данных.
    • INFO: некоторые пользовательские операции, успешный запрос, загрузка ресурсов и т. д. нормальные записи данных
    • ERROR: ошибка JS, ошибка интерфейса и т. д. записи данных типа ошибки
    • DEBUG: зарезервировано разработчиками для возврата записей данных для устранения ошибок путем ручного вызова
    • WARN: зарезервировано для разработчиков, чтобы возвращать записи данных об аномальном поведении пользователей путем ручного вызова
  • CATEGORY: Опишите классификацию данных скрытых точек.
    • TRACK: Жизненный цикл встроенного объекта SDK управляет всеми встроенными данными.
      • WILL_MOUNT: объект sdk должен быть инициализирован и загружен, генерируется идентификатор по умолчанию, и все связанные события отслеживаются.
      • DID_MOUNTED: Инициализация объекта sdk завершена, и асинхронные операции, такие как получение отпечатков пальцев устройства, завершены.
    • AJAX: данные, связанные с AJAX
    • ERROR: данные, связанные с исключением, на странице.
    • PERFORMANCE: данные о производительности
    • OPERATION: Данные, связанные с операциями пользователя.
  • EVENT_NAME: конкретное название события

В соответствии с указанными выше размерами мы можем просто спроектировать следующую архитектуру

В соответствии с архитектурой на приведенном выше рисунке выполняется следующая конкретная разработка кода.

прокси-запрос

В браузере в основном есть 2 метода запроса, один из нихXMLHttpRequest, одинFetch.

Прокси XMLHttpRequest

function NewXHR() {
  var realXHR: any = new OldXHR(); // 代理模式里面有提到过
  realXHR.id = guid()
  const oldSend = realXHR.send;

  realXHR.send = function (body) {
    oldSend.call(this, body)
    //记录埋点
  }
  realXHR.addEventListener('load', function () {
    //记录埋点
  }, false);
  realXHR.addEventListener('abort', function () {
    //记录埋点
  }, false);

  realXHR.addEventListener('error', function () {
    //记录埋点
  }, false);
  realXHR.addEventListener('timeout', function () {
    //记录埋点
  }, false);

  return realXHR;
}

Прокси-выборка

 const oldFetch = window.fetch;
  function newFetch(url, init) {
    const fetchObj = {
      url: url,
      method: method,
      body: body,
    }
    ajaxEventTrigger.call(fetchObj, AJAX_START);
    return oldFetch.apply(this, arguments).then(function (response) {
      if (response.ok) {
       //记录埋点
      } else {
       //上报错误
      }
      return response
    }).catch(function (error) {
      fetchObj.error = error
        //记录埋点      
        throw error
    })
  }

страница монитораPV,UV

При входе на страницу мы алгоритмически генерируем уникальныйsession id, в качестве глобального идентификатора этого скрытого поведения, сообщите идентификатор пользователя, отпечаток пальца устройства и информацию об устройстве. Рассчитывается по отпечатку пальца устройства, когда пользователь не вошел в системуUV,пройти черезsession idрассчитатьPV.

ловушка исключения

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

RUNTIME ERROR

существуетJSсквозьwindow.onerrorа такжеwindow.addEventListener('error', callback)Перехват исключений во время выполнения, обычно используетсяwindow.onerror, это более совместимо.

window.onerror = function(message, url, lineno, columnNo, error) {
    const lowCashMessage = message.toLowerCase()
    if(lowCashMessage.indexOf('script error') > -1) {
      return
    }
    const detail = {
      url: url    
      filename: filename,
      columnNo: columnNo,
      lineno: lineno,
      stack: error.stack,
      message: message
    }
    //记录埋点
}

Script Error

Здесь мы фильтруемScript Error, это в основном вызвано ошибкой стороннего междоменного скрипта, загруженного на страницу, например, размещенного на сторонней CDN.jsсценарий. Такие проблемы сложнее устранить. Решения:

  • ОткрытьCORS(Совместное использование ресурсов между источниками, совместное использование ресурсов между доменами), следующие шаги
    • <srcipt src="another domain/main.js" cossorigin="anonymous"></script>
    • ИсправлятьAccess-Control-Allow-Origin: * | 指定域名
  • использоватьtry catch
      <script scr="crgt.js"></script> //加载crgt脚本,window.crgt = {getUser: () => string}
      try{
          window.crgt.getUser();
      }catch(error) {
          throw error // 输出正确的错误堆栈
      }
    

Promise reject

jsНе удалось передать асинхронное исключениеonerrorЗахват метода, когда объект Promise отклоняется и не обрабатывается одновременно броситunhandledrejectionОшибка не будет поймана вышеописанным методом, поэтому вам нужно добавить отдельное событие обработки.

window.addEventListener("unhandledrejection", event => {
  throw event.reason
});

Исключение при загрузке ресурсов

В браузере можноwindow.addEventListener('error', callback)способ отслеживать исключения загрузки ресурсов, такие какjsилиcssФайл скрипта отсутствует.

window.addEventListener('error', (event) => {
  if (event.target instanceof HTMLElement) {
    const target = parseDom(event.target, ['src']);
    const detail = {
      target: target,
      path: parseXPath(target),
    }
    //  记录埋点
  }
}, true)

Следите за поведением пользователей

пройти черезaddEventListener clickмониторclickмероприятие

window.addEventListener('click', (event) => {
    //记录埋点
}, true)

здесь через компонентdisplaNameпозиционировать элемент,displaNameПредставляет каталог файлов компонента, напримерsrc/components/Form.jsКомпоненты, экспортированные в файлFormItemпройти черезbabel pluginдобавлять свойства автоматически@components/Form.FormItem, либо пользователь активно добавляет в компонентstaticАтрибутыdisplayName.

Изменения маршрутизации страницы

  • hashRouter

Мониторинг изменений хэша страницы и анализ хэша

window.addEventListener('hashchange', event => {
  const { oldURL, newURL } = event;
  const oldURLObj = url.parseUrl(oldURL);
  const newURLObj = url.parseUrl(newURL);
  const from = oldURLObj.hash && url.parseHash(oldURLObj.hash);
  const to = newURLObj.hash && url.parseHash(newURLObj.hash);
  if(!from && !to ) return;
  // 记录埋点
})

Следить за страницей, чтобы уйти

пройти черезaddEventListener beforeunloadПрослушивание событий ухода со страницы

window.addEventListener('beforeunload', (event) => {
    //记录埋点
})

Архитектура SDK

class Observable {
    constructor(observer) {
        observer(this.emit)
    }
    emit = (data) => {
        this.listeners.forEach(listener => {
            listener(data)
        })
    }
    listeners = [];
    
    subscribe = (listener) => {
        this.listeners.push(listeners);
        return () => {
            const index = this.listeners.indexOf(listener);
            if(index === -1) {
                return false
            }
            
            this.listeners.splice(index, 1);
            return true;
        }
     }
}
const clickObservable = new Observable((emit) => {
    window.addEventListener('click', emit)
})

Однако, имея дело сajax, необходимо объединить несколько данных вместе, необходимо выполнить операцию слияния, это не так элегантно, и его трудно адаптировать к работе последующего сложного потока данных.

const ajaxErrorObservable = new Observable((emit) => {
    window.addEventListener(AJAX_ERROR, emit)
})

const ajaxSuccessObservable = new Observable((emit) => {
    window.addEventListener(AJAX_SUCCESS, emit)
})
const ajaxTimeoutObservable = new Observable((emit) => {
    window.addEventListener(AJAX_TIMEOUT, emit)
})

можешь выбратьRxJSоптимизировать код

export const ajaxError$ = fromEvent(window, 'AJAX_ERROR', true)
export const ajaxSuccess$ = fromEvent(window, 'AJAX_SUCCESS', true)
export const ajaxTimeout$ = fromEvent(window, 'AJAX_TIMEOUT', true)
ajaxError$.pipe(
    merge(ajaxSuccess$, ajaxTimeout$), 
    map(data=> (data) => ({category: 'ajax', data; data}))
    subscribe(data => console.log(data))

пройти черезmerge, mapДва оператора завершают объединение и обработку данных.

поток данных

Структура проекта

  • core
    • event$слияние потоков данных
    • snapshotПолучите снимок текущего устройства, например.url,userID,router
    • trackКласс захороненных точек, комбинированный поток данных и журнал.
  • logger
    • loggerкласс журнала
      • info
      • warn
      • debug
      • error
  • observable
    • ajax
    • beforeUpload
    • opeartion
    • routerChange
    • logger
    • track

Ссылаться на

конец

Самостоятельно построенная система скрытых точек — это вопрос, который требует сотрудничества между интерфейсом и сервером.Если рабочей силы недостаточно, рекомендуется использовать сторонние аналитические плагины, такие какSentryдостаточно для большинства повседневного использования

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