Курсорная пагинация для API: когда она надёжнее OFFSET
OFFSET удобен, пока выборка невелика и не меняется между запросами. На таблице из 1,2 млн строк в PostgreSQL 15 выдача 20 строк с OFFSET 1 000 000 заняла 2,4 секунды, а запрос по курсору выполнялся за 3 мс.
База читает пропущенные строки и отбрасывает их. OFFSET каждый раз отсчитывает позиции от текущего начала выборки, поэтому вставки и удаления между запросами дают дубликаты или пропуски. Курсор хранит ID последней полученной записи и продолжает после неё.
В примере на FastAPI запрос выбирает на одну строку больше лимита: она показывает, есть ли продолжение. При сортировке по времени создания нужен курсор и индекс из двух полей, created_at и ID, иначе записи с одинаковым временем могут пропасть.
Оставляйте OFFSET для небольших стабильных данных и перехода к странице N. Для растущей ленты или синхронизации выбирайте курсор.
OFFSET удобен, пока выборка невелика и не меняется между запросами. На таблице из 1,2 млн строк в PostgreSQL 15 выдача 20 строк с OFFSET 1 000 000 заняла 2,4 секунды, а запрос по курсору выполнялся за 3 мс.
База читает пропущенные строки и отбрасывает их. OFFSET каждый раз отсчитывает позиции от текущего начала выборки, поэтому вставки и удаления между запросами дают дубликаты или пропуски. Курсор хранит ID последней полученной записи и продолжает после неё.
В примере на FastAPI запрос выбирает на одну строку больше лимита: она показывает, есть ли продолжение. При сортировке по времени создания нужен курсор и индекс из двух полей, created_at и ID, иначе записи с одинаковым временем могут пропасть.
Оставляйте OFFSET для небольших стабильных данных и перехода к странице N. Для растущей ленты или синхронизации выбирайте курсор.
❤4
Почему box-shadow не заменяет outline для фокуса
CSS-тень даёт больше свободы в оформлении фокуса. Но в режиме принудительных цветов браузер вычисляет
Простой вариант: обычный
Проверить компонент можно в Chromium DevTools: вкладка Rendering, параметр
CSS-тень даёт больше свободы в оформлении фокуса. Но в режиме принудительных цветов браузер вычисляет
box-shadow как none. Пользователь не видит, какая кнопка в фокусе.Простой вариант: обычный
outline. Если нужна тень, не отключайте контур через outline: none: задайте outline: 2px solid transparent и outline-offset: 2px. В обычном режиме контур прозрачен, а при принудительных цветах становится видимым в палитре пользователя.Проверить компонент можно в Chromium DevTools: вкладка Rendering, параметр
forced-colors со значением active. Добавьте сценарий в чеклист доступности, а разбор Manuel Matuzović используйте как памятку с двумя вариантами CSS.👍4❤1
Как заблокировать отрисовку JavaScript, не останавливая HTML-парсер
Когда компоненту нужно измерить размеры и переставить элементы до первого отображения, блокировка парсера не гарантирует результат: браузер может показать полученный HTML, а скрипт перед компонентом ещё не увидит его узлы.
Атрибут
В разборе Джея Фристоуна скрипт измеряет место в навигации и перед показом переносит лишние пункты в дополнительное меню. Так нет вспышки исходной вёрстки и видимого сдвига. Используйте приём точечно, когда компонент зависит от размеров элементов.
Когда компоненту нужно измерить размеры и переставить элементы до первого отображения, блокировка парсера не гарантирует результат: браузер может показать полученный HTML, а скрипт перед компонентом ещё не увидит его узлы.
Атрибут
blocking="render" у script задерживает отрисовку, но не мешает парсеру читать HTML дальше. Работает с модулями и внешними файлами, но сетевой запрос увеличит задержку. Поэтому скрипт лучше сделать маленьким и встроить в HTML.В разборе Джея Фристоуна скрипт измеряет место в навигации и перед показом переносит лишние пункты в дополнительное меню. Так нет вспышки исходной вёрстки и видимого сдвига. Используйте приём точечно, когда компонент зависит от размеров элементов.
❤1👍1
Как защитить API от повторной оплаты
Клиент не получил ответ и повторил
В разборе на DEV Community показаны три подхода. Клиент создаёт ключ один раз и передаёт его при каждом повторе. Сервер атомарно сохраняет ключ, HTTP-статус и идентификатор платежа, а при дубле возвращает их без нового списания. Если запись определяет адрес почты, из него получают стабильный идентификатор и обновляют одну строку. Проверка версии защищает от одновременных изменений, но сама не делает запрос идемпотентным.
Начните с методов API с побочным эффектом: разделяйте ключи по пользователю и операции, отклоняйте тот же ключ с другими данными и отправьте 50 одновременных запросов, чтобы убедиться, что списание происходит один раз.
Клиент не получил ответ и повторил
POST. Сервер мог уже списать деньги, поэтому повтор может привести ко второй оплате. Идемпотентность решает это: несколько одинаковых запросов дают тот же результат, что один.В разборе на DEV Community показаны три подхода. Клиент создаёт ключ один раз и передаёт его при каждом повторе. Сервер атомарно сохраняет ключ, HTTP-статус и идентификатор платежа, а при дубле возвращает их без нового списания. Если запись определяет адрес почты, из него получают стабильный идентификатор и обновляют одну строку. Проверка версии защищает от одновременных изменений, но сама не делает запрос идемпотентным.
Начните с методов API с побочным эффектом: разделяйте ключи по пользователю и операции, отклоняйте тот же ключ с другими данными и отправьте 50 одновременных запросов, чтобы убедиться, что списание происходит один раз.
🔥1
Как анимировать перестройку CSS Grid без JavaScript
В разборе приёма содержимое каждой плитки привязывают к её ячейке через CSS Anchor Positioning. Перемещение при изменении ширины контейнера анимирует обычный переход свойства
Ячейка Grid виртуальна, поэтому якорем служит дополнительная обёртка. Она получает
Анимацию можно прервать: плитки сразу направятся к новым позициям, не дожидаясь предыдущего перехода. JavaScript не нужен. В Firefox приём сейчас не анимируется, поэтому для интерфейса во всех браузерах понадобится запасной вариант.
В разборе приёма содержимое каждой плитки привязывают к её ячейке через CSS Anchor Positioning. Перемещение при изменении ширины контейнера анимирует обычный переход свойства
inset.Ячейка Grid виртуальна, поэтому якорем служит дополнительная обёртка. Она получает
anchor-name, а anchor-scope позволяет повторять это имя в других ячейках без конфликтов. Блоку с контентом задают абсолютное позиционирование и фиксированные размеры, чтобы он не растягивался при движении.Анимацию можно прервать: плитки сразу направятся к новым позициям, не дожидаясь предыдущего перехода. JavaScript не нужен. В Firefox приём сейчас не анимируется, поэтому для интерфейса во всех браузерах понадобится запасной вариант.
🔥3
Как защитить списание кредитов в Django от гонки запросов
У аккаунта один кредит. Два запроса читают баланс до первого сохранения, оба проходят проверку и записывают ноль. Сервис принимает две генерации, хотя баланс не уходит в минус. Поэтому проверка на отрицательный баланс баг не ловит.
В руководстве ошибку воспроизводят, затем закрывают транзакцией базы данных и блокировкой строки аккаунта. Проверку баланса, списание и запись принятого запроса объединяют в одну защищённую операцию. Пример работает на Django 5.2, Django REST Framework 3.16 и PostgreSQL 17. SQLite не подходит: он не реализует нужную блокировку строк.
В разборе freeCodeCamp есть настройка проекта и тест двух запросов, которые претендуют на последний кредит. Открывайте его перед ревью логики лимитов: найдите разрыв между чтением и записью, затем перенесите решение внутрь транзакции.
У аккаунта один кредит. Два запроса читают баланс до первого сохранения, оба проходят проверку и записывают ноль. Сервис принимает две генерации, хотя баланс не уходит в минус. Поэтому проверка на отрицательный баланс баг не ловит.
В руководстве ошибку воспроизводят, затем закрывают транзакцией базы данных и блокировкой строки аккаунта. Проверку баланса, списание и запись принятого запроса объединяют в одну защищённую операцию. Пример работает на Django 5.2, Django REST Framework 3.16 и PostgreSQL 17. SQLite не подходит: он не реализует нужную блокировку строк.
В разборе freeCodeCamp есть настройка проекта и тест двух запросов, которые претендуют на последний кредит. Открывайте его перед ревью логики лимитов: найдите разрыв между чтением и записью, затем перенесите решение внутрь транзакции.
❤2
Как проверять CSS после рефакторинга с ИИ
Пять ИИ-инструментов получили HTML и CSS карточки и одинаковый запрос на рефакторинг. Все убрали очевидные повторы, но хуже справились с каскадом: чистка могла менять оформление и поведение компонента.
Одна из ловушек:
После рефакторинга проверяйте наведение, динамические классы, обрезку текста и границы селекторов. В тесте LogRocket Blog собраны семь ловушек, таблица результатов для пяти инструментов и файлы всех вариантов.
Пять ИИ-инструментов получили HTML и CSS карточки и одинаковый запрос на рефакторинг. Все убрали очевидные повторы, но хуже справились с каскадом: чистка могла менять оформление и поведение компонента.
Одна из ловушек:
.promo-active .card .badge имеет ту же специфичность, что и .card .badge.badge-new. Здесь !important гарантирует оранжевый цвет промобейджа независимо от порядка правил. Без него результат зависит от порядка. В обычном состоянии карточки ошибка не видна.После рефакторинга проверяйте наведение, динамические классы, обрезку текста и границы селекторов. В тесте LogRocket Blog собраны семь ловушек, таблица результатов для пяти инструментов и файлы всех вариантов.
❤3
Как перенести поиск по 272 тысячам слов в браузер на Rust и WebAssembly
Поисковик работает как статический сайт: JavaScript загружает и распаковывает словари, управляет интерфейсом, а модуль WebAssembly, собранный из Rust, индексирует слова, фильтрует и сортирует результаты. Запросы остаются на устройстве пользователя, сервер поиска не нужен.
Словарь разбит на 26 сжатых файлов по первой букве. Для набора RETAINS браузер скачивает семь нужных частей. Слова с одинаковым набором букв собираются под общим ключом, где буквы отсортированы по алфавиту. Движок сравнивает их количество в ключе и запросе, поэтому отбрасывает целые группы до проверки отдельных слов.
Разбор архитектуры пригодится при проектировании браузерного инструмента с тяжёлыми локальными вычислениями. Учтите ограничение: модуль работает синхронно в основном потоке, поэтому широкий запрос может заблокировать интерфейс.
Поисковик работает как статический сайт: JavaScript загружает и распаковывает словари, управляет интерфейсом, а модуль WebAssembly, собранный из Rust, индексирует слова, фильтрует и сортирует результаты. Запросы остаются на устройстве пользователя, сервер поиска не нужен.
Словарь разбит на 26 сжатых файлов по первой букве. Для набора RETAINS браузер скачивает семь нужных частей. Слова с одинаковым набором букв собираются под общим ключом, где буквы отсортированы по алфавиту. Движок сравнивает их количество в ключе и запросе, поэтому отбрасывает целые группы до проверки отдельных слов.
Разбор архитектуры пригодится при проектировании браузерного инструмента с тяжёлыми локальными вычислениями. Учтите ограничение: модуль работает синхронно в основном потоке, поэтому широкий запрос может заблокировать интерфейс.
❤1
Как уместить динамическую карту мира в 10 КБ
Карта Calibre показывает пользовательские сессии по странам, а цвет передаёт оценку опыта на основе производительности сайта. При сборке создаётся статический SVG; приложение загружает его и задаёт цвета странам через CSS-переменные.
Скрипт на Node.js упрощает границы в GeoJSON библиотекой Turf, переносит их на карту через d3-geo и относит ячейки к странам. Один шестиугольник описан в SVG один раз, а 2164 экземпляра ссылаются на него. Файл весит 144 КБ, после Gzip при передаче остаётся 10 КБ.
Приём подходит для лёгкой обзорной карты без масштабирования и панорамирования. Упрощение съедает детали: Тасмания не помещается в ячейку шириной около 4 пикселей, а США разрываются по краям. В разборе Calibre показаны конвейер сборки и настройка светлой и тёмной тем.
Карта Calibre показывает пользовательские сессии по странам, а цвет передаёт оценку опыта на основе производительности сайта. При сборке создаётся статический SVG; приложение загружает его и задаёт цвета странам через CSS-переменные.
Скрипт на Node.js упрощает границы в GeoJSON библиотекой Turf, переносит их на карту через d3-geo и относит ячейки к странам. Один шестиугольник описан в SVG один раз, а 2164 экземпляра ссылаются на него. Файл весит 144 КБ, после Gzip при передаче остаётся 10 КБ.
Приём подходит для лёгкой обзорной карты без масштабирования и панорамирования. Упрощение съедает детали: Тасмания не помещается в ячейку шириной около 4 пикселей, а США разрываются по краям. В разборе Calibre показаны конвейер сборки и настройка светлой и тёмной тем.
❤1
Почему HTML-атрибут accept ухудшает загрузку файлов и чем его заменить
Атрибут
Защитой такой фильтр всё равно не служит: перетаскивание файла позволяет его обойти, размер он не проверяет, а Firefox на Android его не поддерживает. Значит, обработка ошибок всё равно нужна.
Практический вариант: заранее перечислить допустимые форматы в подсказке, но не рассчитывать, что её прочитают. После выбора проверить файл и сразу показать ошибку, по которой понятно, что исправить. Аргументы и примеры интерфейса собраны в разборе атрибута accept.
Атрибут
accept в поле загрузки оставляет доступными только заданные типы файлов, а остальные делает серыми. Часть пользователей не замечает это состояние, нажимает на недоступный файл и решает, что интерфейс сломан.Защитой такой фильтр всё равно не служит: перетаскивание файла позволяет его обойти, размер он не проверяет, а Firefox на Android его не поддерживает. Значит, обработка ошибок всё равно нужна.
Практический вариант: заранее перечислить допустимые форматы в подсказке, но не рассчитывать, что её прочитают. После выбора проверить файл и сразу показать ошибку, по которой понятно, что исправить. Аргументы и примеры интерфейса собраны в разборе атрибута accept.
❤2👍2👎1
Фреймворки меняются, а логика и процессы в работе над проектами всегда останутся главными. В подборке разбираем, как задача проходит путь от бэклога до релиза, какие стратегии деплоя не роняют прод и как подходить к модернизации легаси, а заодно как перестроить мышление при переходе с React на Angular. Дополняют её тексты про работу с выделенной командой и безопасность, от многофакторки до ловушек формального контроля в ИБ.
Как выстроить работу с выделенной командой
Как работает IT-команда: путь задачи от бэклога до релиза
7 стратегий модернизации легаси
Стратегии деплоя, которые не роняют прод
Как сделать ИБ по-настоящему надёжной
Зачем бизнесу многофакторка
Использование разных фреймворков качает мозг
Как выстроить работу с выделенной командой
Как работает IT-команда: путь задачи от бэклога до релиза
7 стратегий модернизации легаси
Стратегии деплоя, которые не роняют прод
Как сделать ИБ по-настоящему надёжной
Зачем бизнесу многофакторка
Использование разных фреймворков качает мозг
👍2🔥1
Как публиковать блог через Standard.site и AT Protocol
Standard.site задаёт схему JSON-записей для статей в сети Bluesky. Материал получает известные сервисам поля, поэтому pckt, Docs.surf, potatonet и Leaflet могут показать его без отдельной интеграции, а Bluesky собирает расширенное превью.
Для запуска нужны две записи: одна описывает издание, вторая статью. В разборе Piccalilli показана реализация на JavaScript через официальный пакет
Я сохранил этот маршрут для эксперимента с переносимым блогом: можно начать с одной статьи и проверить, какие сервисы AT Protocol её подхватят. Пароль приложения стоит держать в переменной окружения: он даёт полный доступ к аккаунту и обходит многофакторную аутентификацию.
Standard.site задаёт схему JSON-записей для статей в сети Bluesky. Материал получает известные сервисам поля, поэтому pckt, Docs.surf, potatonet и Leaflet могут показать его без отдельной интеграции, а Bluesky собирает расширенное превью.
Для запуска нужны две записи: одна описывает издание, вторая статью. В разборе Piccalilli показана реализация на JavaScript через официальный пакет
@atproto/api: авторизация, создание записей и необязательная проверка связи с доменом.Я сохранил этот маршрут для эксперимента с переносимым блогом: можно начать с одной статьи и проверить, какие сервисы AT Protocol её подхватят. Пароль приложения стоит держать в переменной окружения: он даёт полный доступ к аккаунту и обходит многофакторную аутентификацию.
🔥1
Как сверстать диагональную шапку таблицы доступнее
Эрик Мейер разбирает шапку таблицы Apollo 16: угол разделён диагональю между подписями строк и столбцов. Доступность двух
Он оставил подписи в двух строках
В разборе Эрика Мейера есть код. Базовые тесты не выявили крупных проблем, но гарантии для всех экранных дикторов нет. Если нужна такая ячейка, сохраните табличную семантику, проверьте раскладку в Safari и навигацию в экранных дикторах.
Эрик Мейер разбирает шапку таблицы Apollo 16: угол разделён диагональю между подписями строк и столбцов. Доступность двух
span в одной ячейке показалась ему сомнительной.Он оставил подписи в двух строках
thead, растянул заголовки на обе строки через rowspan и наложил вторую строку на первую. Диагональ рисует CSS-градиент. Safari не применяет относительное позиционирование к thead, поэтому потребовался обход через @supports.В разборе Эрика Мейера есть код. Базовые тесты не выявили крупных проблем, но гарантии для всех экранных дикторов нет. Если нужна такая ячейка, сохраните табличную семантику, проверьте раскладку в Safari и навигацию в экранных дикторах.
❤2
Как проверять все пути к res.redirect() в Node.js
В cas-authentication-user 0.3.0 проверка отклоняла внешний
Аудит начинайте с
В 0.4.0 проверяют результат разбора URL, а внешний адрес заменяют на
В cas-authentication-user 0.3.0 проверка отклоняла внешний
returnTo, но брала запасной путь из адреса запроса. url.parse() превращал /\bad.example.com в //bad.example.com, а браузер считал это адресом чужого домена. Исправление одного открытого редиректа оставило второй в той же функции.Аудит начинайте с
res.redirect(): перечислите все входящие значения и проверьте запасную ветку после отказа валидатора. Она работает на атакующем вводе и тоже должна вернуть безопасный адрес.В 0.4.0 проверяют результат разбора URL, а внешний адрес заменяют на
/. В разборе Megapixel99 на DEV Community есть код. Если пакет есть в проекте, обновитесь до 0.4.0.❤1👍1
Что делает архитектор решений и как подготовиться к этой роли
Веб-разработчику, который хочет влиять не на один сервис, а на систему целиком, пригодится взгляд архитектора решений. Он переводит бизнес-задачу в набор доработок и связей между системами.
Сначала архитектор разбирает требования на функции, распределяет их по системам и проектирует обмен данными. Итог оформляет в документ с диаграммами систем, интеграций, процессов и ролей. Если пропустить систему, её доработку не учтут в бюджете, а сроки могут сдвинуться.
Перед собеседованием откройте дорожную карту профессии: проверьте знания очередей, баз данных, безопасности и интеграций, затем потренируйтесь задавать уточняющие вопросы и быстро набрасывать схему решения. Там же разобраны онбординг, первый год, рабочий день и перспективы роли.
Веб-разработчику, который хочет влиять не на один сервис, а на систему целиком, пригодится взгляд архитектора решений. Он переводит бизнес-задачу в набор доработок и связей между системами.
Сначала архитектор разбирает требования на функции, распределяет их по системам и проектирует обмен данными. Итог оформляет в документ с диаграммами систем, интеграций, процессов и ролей. Если пропустить систему, её доработку не учтут в бюджете, а сроки могут сдвинуться.
Перед собеседованием откройте дорожную карту профессии: проверьте знания очередей, баз данных, безопасности и интеграций, затем потренируйтесь задавать уточняющие вопросы и быстро набрасывать схему решения. Там же разобраны онбординг, первый год, рабочий день и перспективы роли.
❤1👍1🔥1
Как связать Lottie-анимацию с кликами через DOM
В веб-игрушке Stress Release нужна была точная реакция на клик. Физический движок выдавал правдоподобное движение, но мог подменить заданные кадры расчётами. Поэтому команда выбрала Lottie.
Клик переводят в локальные координаты персонажа, а расстояние до центра вычисляют через
В разборе Smashing Magazine есть код расчёта попадания, управления кадрами и изменения размеров через CSS-переменные. Приём пригодится, когда реакция по макету важнее физической симуляции.
В веб-игрушке Stress Release нужна была точная реакция на клик. Физический движок выдавал правдоподобное движение, но мог подменить заданные кадры расчётами. Поэтому команда выбрала Lottie.
Клик переводят в локальные координаты персонажа, а расстояние до центра вычисляют через
Math.hypot(). Оно определяет очки и интенсивность отклика; анимация взрыва появляется в месте нажатия. Код проигрывает через Lottie нужный отрезок кадров, блокирует новые клики до его завершения и возвращает персонажа к циклу ожидания.В разборе Smashing Magazine есть код расчёта попадания, управления кадрами и изменения размеров через CSS-переменные. Приём пригодится, когда реакция по макету важнее физической симуляции.
❤1👍1
Как собрать турнирную сетку FIFA на CSS Grid и subgrid
На странице FIFA каждый столбец раунда вынесен в отдельный элемент: разметка повторяет экран. В разборе макета показана другая структура: один элемент на раунд, внутри две группы матчей по сторонам.
Сетка получает восемь колонок и четыре строки. Вложенный раунд растягивается по ней и через
Откройте этот разбор, когда дизайн требует симметричной схемы, а разметка начинает копировать каждую визуальную колонку. На планшете макет сохраняет структуру с горизонтальной прокруткой, на узком экране все раунды выстраиваются слева.
На странице FIFA каждый столбец раунда вынесен в отдельный элемент: разметка повторяет экран. В разборе макета показана другая структура: один элемент на раунд, внутри две группы матчей по сторонам.
Сетка получает восемь колонок и четыре строки. Вложенный раунд растягивается по ней и через
subgrid наследует те же линии, поэтому группы можно поставить в первую и последнюю колонки без отдельных обёрток. Матчи по вертикали автор распределяет с помощью Flexbox: каждый занимает равную долю доступной высоты, и соединительные линии сходятся с центрами карточек.Откройте этот разбор, когда дизайн требует симметричной схемы, а разметка начинает копировать каждую визуальную колонку. На планшете макет сохраняет структуру с горизонтальной прокруткой, на узком экране все раунды выстраиваются слева.
🔥3❤1👍1
Как работает балансировка нагрузки в веб-бэкенде
Балансировщик принимает запрос раньше API и выбирает один из нескольких серверов. Так приложение масштабируется горизонтально: вместо наращивания процессора и памяти одной машины можно добавлять серверы, а при отказе одного остальные продолжат отвечать.
Схема распределения зависит от нагрузки. Циклический алгоритм Round Robin по очереди отправляет запросы на каждый сервер, но не видит, насколько они заняты. Алгоритм наименьшего числа соединений выбирает сервер с наименьшим числом активных подключений и подходит, когда запросы выполняются разное время.
Откройте разбор на DEV Community перед проектированием API: внутри сравнение алгоритмов и уровней балансировки, проверки состояния серверов и привязка сессий.
Балансировщик принимает запрос раньше API и выбирает один из нескольких серверов. Так приложение масштабируется горизонтально: вместо наращивания процессора и памяти одной машины можно добавлять серверы, а при отказе одного остальные продолжат отвечать.
Схема распределения зависит от нагрузки. Циклический алгоритм Round Robin по очереди отправляет запросы на каждый сервер, но не видит, насколько они заняты. Алгоритм наименьшего числа соединений выбирает сервер с наименьшим числом активных подключений и подходит, когда запросы выполняются разное время.
Откройте разбор на DEV Community перед проектированием API: внутри сравнение алгоритмов и уровней балансировки, проверки состояния серверов и привязка сессий.
❤2👍1
Как читать HTML-реликты из эпохи браузерных войн
В старом
Другие теги защищали страницу от вмешательства сторонних программ. Skype Toolbar превращал номера телефонов в кнопки и мог ломать вёрстку, поэтому сайт отключал его отдельным метатегом. Baidu пропускала мобильные страницы через свой сервис, перестраивала макет, удаляла стили и подменяла рекламу; от этой обработки тоже можно было отказаться в разметке.
Разбор Antiquated HTML Snippets and Artefacts пригодится при ревизии унаследованных шаблонов: сначала выясните, какую интеграцию обслуживала незнакомая строка и существует ли её цель, а затем решайте, удалять ли её.
В старом
head можно встретить строки, смысл которых уже не восстановить по имени. Например, X-UA-Compatible заставлял Internet Explorer выбирать самый новый доступный режим документа, а условные комментарии показывали разную разметку отдельным версиям браузера.Другие теги защищали страницу от вмешательства сторонних программ. Skype Toolbar превращал номера телефонов в кнопки и мог ломать вёрстку, поэтому сайт отключал его отдельным метатегом. Baidu пропускала мобильные страницы через свой сервис, перестраивала макет, удаляла стили и подменяла рекламу; от этой обработки тоже можно было отказаться в разметке.
Разбор Antiquated HTML Snippets and Artefacts пригодится при ревизии унаследованных шаблонов: сначала выясните, какую интеграцию обслуживала незнакомая строка и существует ли её цель, а затем решайте, удалять ли её.
❤2
Как ловить утечки памяти в SPA с помощью Playwright
Обычные сквозные тесты создают новый контекст браузера для каждого сценария, поэтому небольшая утечка не успевает вырасти. Тест на выносливость делает иначе: 200 раз открывает и закрывает одну панель в том же контексте, затем сравнивает число DOM-узлов и обработчиков событий до и после цикла.
Метрики Playwright получает через протокол Chrome DevTools, поэтому приём работает только в Chromium. Таймеры можно проверить с ускоренными часами страницы: 18 секунд на каждом проходе превращают 200 циклов в час работы таймеров.
Из-за разброса показаний такую проверку лучше поставить в ночной запуск. Код
Обычные сквозные тесты создают новый контекст браузера для каждого сценария, поэтому небольшая утечка не успевает вырасти. Тест на выносливость делает иначе: 200 раз открывает и закрывает одну панель в том же контексте, затем сравнивает число DOM-узлов и обработчиков событий до и после цикла.
Метрики Playwright получает через протокол Chrome DevTools, поэтому приём работает только в Chromium. Таймеры можно проверить с ускоренными часами страницы: 18 секунд на каждом проходе превращают 200 циклов в час работы таймеров.
Из-за разброса показаний такую проверку лучше поставить в ночной запуск. Код
soak(), двойную сборку мусора и пример порога для DOM-узлов автор собрал в разборе теста.❤4