TGStat
TGStat
Qidiruv uchun matnni kiriting
Ilg‘or kanal qidiruvi
  • flag Uzbek
    Sayt tili
    flag Russian flag English flag Uzbek
  • Saytga kirish
  • Katalog
    Kanal va guruhlar katalogi Hududiy to‘plamlar Tematik to‘plamlar Платные каналы Kanallar qidiruvi
    Kanal/guruh qo‘shish
  • Reytinglar
    Kanallar reytingi Guruhlar reytingi Postlar reytingi
    Brendlar va shaxslar reytingi
  • Analitika
  • Postlarda qidiruv
  • Telegram'ni kuzatish
  • Targ‘ibot
    Yandex Business orqali reklama TGStat Agency orqali kanallarda reklama TGStat.ru saytida reklama
@alexnozer_dev

26 Aug, 17:04

Telegram'da ochish Ulashish Shikoyat qilish

Не стоит полагаться на User Agent

User Agent sniffing — это техника поиска в строке User Agent названия браузера и его версии для определения того, с какого браузера пришёл пользователь. Это можно использовать во благо для оптимизаций и загрузки полифилов.

На практике это применялось для трекинга и фингерпринтинга. Поэтому браузеры уже давно пихают в User Agent всё подряд и врут. Поэтому User Agent sniffing — крайне ненадёжная и нестабильная штука. На днях я столкнулся с этим на практике.

При аудите производительности сайта во вкладке Performance я заметил много операций принудительной перекомпоновки (forced reflow). Это когда чтение и запись геометрии элементов в JS приводит к пересчёту стилей.

Виновником стал скрипт autosizes. Это полифил атрибута sizes="auto" у и . Он запрашивает размеры через getBoundingClientRect(), что и приводит к принудительным перекомпоновкам. Сам скрипт подключается автоматически.

Интересно то, что отладка велась в Chrome версии 151, а поддержка sizes="auto" реализована ещё в версии 126. То есть полифил выполняет работу в браузере, где функция поддерживается. Обычно в таких случаях полифил не отрабатывает.

Этот полифил не исключение. На страницу встроен скрипт, в котором есть функция проверки перед загрузкой скрипта. Также в самом скрипте функция дублируется. То есть проверка выполняется даже дважды. Вот код этой функции:

const polyfillAutoSizes = () => {
if (!window.PerformanceObserver?.supportedEntryTypes?.includes("paint")) {
return false
}
const userAgent = navigator.userAgent;
const platform = navigator.platform;
const maxTouchPoints = navigator.maxTouchPoints
|| 0;
const isIOS = /iPad|iPhone|iPod/.test(platform)
|| platform === "MacIntel"
&& maxTouchPoints > 1;
const isMacSafari = platform.indexOf("Mac") === 0
&& /Safari/.test(userAgent)
&& !/Chrome|Chromium|CriOS|FxiOS|Edg|OPR|Android/.test(userAgent);
const isAppleSafari = isIOS || isMacSafari;
const browserMajorVersion = pattern => {
const match = userAgent.match(pattern);
return match
? parseInt(match[1], 10)
: null
}

const chromeVersion = browserMajorVersion(
/Chrome\/(\d+)/
);
if (chromeVersion !== null) {
return chromeVersion < 126
}
const safariVersion = isAppleSafari
? browserMajorVersion(
/Version\/(\d+).*Safari\//
)
: null;
if (safariVersion !== null) {
return safariVersion < 27
}
const firefoxVersion = browserMajorVersion(
/Firefox\/(\d+)/
);
if (firefoxVersion !== null) {
return firefoxVersion < 150
}
return true
}
;
if (!polyfillAutoSizes()) {
return
}
В нём проверяется версия Chrome, Safari и Firefox на основе строки User Agent. Скрипт не должен подключаться, если версия Chrome меньше 126. Но он подключается и работает в Chrome 151. Где-то функция дала сбой и вернула true.

Выяснилось, что в моей строке User Agent не было ни Chrome, ни Safari, ни Firefox. Логика прошла все проверки, нигде не случился early return и в итоге дошло до return true. Вот такая у меня строка User Agent, где ни Chrome, ни его версии:

Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1
В теории User Agent выглядит как источник данных о браузере и версии. Может показаться вполне разумным брать оттуда информацию для активации полифила. Ведь известны браузеры и версии, где функция поддерживается.

На деле же строка User Agent максимально непредсказуемая, браузеры постоянно её меняют и могут врать, что и произошло в моём случае. В строке User Agent в Chrome не было ни намёка на Chrome. Браузеры делают это специально.

При разработке полифилов надёжнее будет полагаться на обнаружение функций (feature detection) — проверку фактического наличия и работоспособности функции в браузере. Это и должно служить основанием для подключения полифила.

Авторы полифила это уже поняли, поэтому открыт PR c заменой User Agent sniffing на обнаружение функций. Создаётся реальное изображение, ему задаются CSS-свойства, устанавливается атрибут и производится проверка вычисляемого значения.

const polyfillAutoSizes = () => {
// Avoid polyfilling if the browser is too old and doesn't support performance observer and paint timing
if (
!('PerformanceObserver' in window)
|| !PerformanceObserver
.supportedEntryTypes
.includes('paint')
) {
return false;
}

// Check UA styles for expected styles to support sizes auto.
const img = document.createElement('img');
img.style.setProperty(
'display',
'none',
'important'
);
img.style.setProperty(
'contain',
'revert',
'important'
);
img.sizes = 'auto';
document.documentElement.append(img);
const {contain} = getComputedStyle(img);
img.remove();
return contain !== 'size';
};

if (!polyfillAutoSizes()) {
return;
}
Этот способ намного надёжнее, хотя не всегда возможен. Есть функции, поддержку которых нельзя или сложно проверить таким образом. Тем не менее, во многих случаях это гораздо лучше проверки на основе User Agent.

#js #performance

694 0 3 14
Katalog
Kanal va guruhlar katalogi Kanallar to‘plamlari Kanallar qidiruvi Kanal/guruh qo‘shish
Reytinglar
Telegram-kanallar reytingi Telegram-guruhlar reytingi Postlar reytingi Brendlar va shaxslar reytingi
API
Statistika API'si Postlar qidiruvi API'si API Callback
Kanallarimiz
@TGStat @TGStat_Chat @telepulse @TGStatAPI
O‘qish
Академия TGStat Telegram tadqiqoti 2019 Telegram tadqiqoti 2021 Telegram tadqiqoti 2023
Kontaktlar
Справочный центр Qo‘llab-quvvatlash Email Vakansiyalar
Har xil narsalar
Foydalanuvchi shartnomasi Maxfiylik siyosati Ommaviy oferta
Botlarimiz
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot