«Эти вещи на переднем крае» ⑤ Индикатор эффективности позиционирования FMP

JavaScript
«Эти вещи на переднем крае» ⑤ Индикатор эффективности позиционирования FMP

Что такое FMP?

Возможно, вы знакомы с термином "время белого экрана". Это один из показателей производительности страницы, который мы собирали в эпоху "слэш-энд-огня". При сложности интерфейсной разработки время белого экрана не имеет существенного значения. .На его месте стоит FMP.

Давайте сначала введем некоторые связанные термины.

  • FP (First Paint): первая отрисовка, отмечающая момент времени, когда браузер отображает любое содержимое экрана, которое визуально отличается от экрана перед навигацией.
  • FCP (First Contentful Paint): первая отрисовка контента, отмечающая время, когда браузер отображает первый контент DOM, который может быть текстом, изображениями, SVG или<canvas>и т.д. элементы
  • FMP (First Meaning Paint): первый эффективный рисунок, отмечающий момент времени, когда рендеринг элемента главного героя завершен, элемент главного героя может быть элементом управления видео на веб-сайте с видео, рамка страницы веб-сайта с контентом также может быть заглавное изображение сайта ресурса и т. д.

По сравнению с FP и FCP, FMP является наиболее важным показателем производительности, который больше всего беспокоит наш интерфейс. Google определяет его как момент времени «полезно ли это?». Однако «полезен ли он?» сложно определить в общем виде, поэтому до сих пор нет стандартного вывода API.

Часто существует несколько способов расчета «относительно точного» FMP в сообществе, так называемая относительная точность относительно реального проекта.

  1. Активная отчетность: разработчик сообщает о времени в позиции «Значение» соответствующей страницы.
  2. Расчет веса: в соответствии с элементами страницы рассчитайте время рендеринга элемента с наибольшим весом.
  3. Расчет тренда: Рассчитайте значение FMP в соответствии с тенденцией изменения dom в течение периода рендеринга.

В этой статье речь пойдет о втором способе.

Позиционирование веса

Так называемый вес, то есть переход элементов страницы к определенному DOM или группе DOM с наибольшим «значением веса» в соответствии с согласованным «соотношением веса», а затем использовать его «момент времени загрузки» или «конечная точка загрузки» как отображение FMP.

Расчет веса

тег узла

Если вы хотите пометить узлы DOM поэтапно, у вас должна быть возможность отслеживать изменения DOM, к счастью, HTML5 дает нам такую ​​возможность.

MutationObserver, замену функции Mutation Events, которая является частью спецификации DOM3 Events. Он может выполнять обратные вызовы при изменении указанного DOM.

MutationObserver имеет три метода

  • disconnect()

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

  • observe()

    Настройте MutationObserver, чтобы он начал получать уведомления через функцию обратного вызова, когда изменения DOM соответствуют заданным параметрам.

  • takeRecords()

    Удаляет все ожидающие уведомления из очереди уведомлений MutationObserver и возвращает их в новый массив объектов MutationRecord.

global.mo = new MutationObserver(() => { 
    /* callback: DOM 节点设置阶段性标记 */
});

/**
 * mutationObserver.observe(target[, options])
 * target - 需要观察变化的 DOM Node。
 * options - MutationObserverInit 对象,配置需要观察的变化项。
 * 更多 options 的介绍请参考 https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserverInit#%E5%B1%9E%E6%80%A7
 **/
global.mo.observe(document, {
  childList: true,  // 监听子节点变化(如果subtree为true,则包含子孙节点)
  subtree: true // 整个子树的所有节点
});

На следующем рисунке показан грубый анализ процесса рендеринга обычной отдельной страницы.

  • Подготовительный этап: Навигационный этап, в процессе подключения соответствующих
  • Этап 1: первый этап рендеринга байтов также является первым эффективным изменением дерева FCP и DOM.
  • Этап 2: Базовый рендеринг кадра завершен.
  • Этап 3: получите данные и визуализировать его на вид
  • Фаза IV: загружено изображение, процесс загрузки не отмечен

На самом деле, между первой и третьей стадией еще очень много изменений DOM, срабатывание события Mutation Observer происходит не синхронно, а асинхронно, то есть до тех пор, пока не закончатся все DOM-операции в текущей «стадии».

Mutation Observer имеет следующие особенности

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

существуетloadПосле запуска события тег каждого этапа был отмечен на теге

Здесь с "_ti』Отметьте ключ прошлой ночью.

При маркировке необходимо записать текущий узел времени для резервного копирования

// 伪代码
function callback() {
    global.timeStack[++_ti] = performance.now(); // 记时间
    doTag(_ti); // 打标记
}

После разметки дождитесь расчета момента нагрузки и вдавите обратно.

Рассчитать значение веса

Вообще говоря

  • Элемент с большей долей просмотра, скорее всего, будет главным элементом.
  • Видео с большей вероятностью будут главными героями, чем изображения
  • svgа такжеcanvasтакже важно
  • Другие элементы можно рассчитать по обычному дом
  • Фоновое изображение зависит от ситуации, можете вы его запомнить или нет
Первый шаг: простой и грубый, по размеру
// 伪代码
function weightCompute(node){
    let {
        width,
        height,
        left,
        top
    } = node.getBoundingClientRect();
    
    // 排除视图外的元素
    if(isOutside(width, height, left, top)){
        return 0;
    }
    let wts = TAG_WEIGHT_MAP[node.tagName]; // 约定好的权重比
    let weight = width * height * wts; // 直接乘,或者更细粒度的计算 wts(width, height, wts)
    return {
        weight, 
        wts, 
        tagName: node.tagName, 
        ti: node.getAttribute("_ti"),
        node
    };
}
Шаг вторая: свинец деривация в зависимости от веса

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

// 伪代码
function getCoreNode(node){
    let list = nodeTraversal(node); // 递归计算每个标记节点的权重值
    return getNodeWithMaxWeight(list); // weight 最大的元素
}
Шаг 3: Потратьте время в соответствии с типом элемента

Разные элементы получают время по-разному

  • Нормальные элементы: рассчитываются по времени маркера
  • Картинки и видео: Рассчитывается по соответствующему времени окончания ресурса.
  • С фоновыми элементами: его можно рассчитать в соответствии с соответствующим временем окончания фонового ресурса или его можно рассчитать в соответствии с обычными элементами.
// 伪代码
function getFMP(){
    let coreObj = getCoreNode(document.body),
        fmp = -1;
    let {
        tagName,
        ti,
        node
    } = coreObj;
    
    switch(tagName){
        case 'IMG':
        case 'VIDEO':
            let source = node.src;
            let { responseEnd } = performance.getEntries().find(item => item.name === source);
            fmp = responseEnd || -1;
            break;
        default:
            if(node.style.backgroundImage){
                // 普通元素的背景处理
            }else{
               fmp = global.timeStack[+ti]; 
            }
    }
    return fmp;
}

Верификация регрессии

Возьмите нашу демонстрационную страницу в качестве примера. Для аналогичных веб-сайтов электронной коммерции мы хотим получить момент времени «Фаза 2» или «Фаза 3» в качестве значения FMP.

Поскольку мы не хотим, чтобы фон «элемента главного героя» или соответствующее время «элемента главного героя изображения» учитывались в значении FMP, мы понижаем рейтинг элементов ресурсов, таких как «изображение» и «видео». к обычным элементам для расчета.

Мы проводим проверку симуляции в условиях Chrome [ Disable cache / Fast 3G ].

Расчетное значение FMP составляет 4730,7 мс, значение, отслеживаемое Chrome Performance, составляет около 4950 мс, а ошибка составляет около 200 мс.

Мы надеемся, что если ограничение скорости будет снято, значение FMP будет ближе к «First Meaning Paint».

Перепечатка с указанием источника

Автор: деревянное перо zwwill

Первый адрес:zwwill/blog#32