Почему список активных пользователей прыгает при переключении вкладок
Узнайте причины скачков списка активных пользователей в Edge и Firefox при переключении вкладок и как это исправить.
Почему при переключении между вкладками в браузерах MS Edge и Firefox список активных пользователей в веб-приложении ‘скачет’?
У меня есть веб-приложение, работающее в корпоративной доменной сети. В приложении есть раздел ‘Активные пользователи’, который обновляется каждые 15 секунд. Система работает следующим образом:
- Каждые 5 секунд в базу данных записывается текущее время как время последней активности пользователя
- Каждые 15 секунд приложение запрашивает список активных пользователей, сравнивая текущее время со временем последней активности
- Если разница во времени превышает 15 секунд, пользователь считается неактивным и не отображается в списке
Проблема: при переключении на другие вкладки в браузерах MS Edge и Firefox список активных пользователей начинает ‘прыгать’ - пользователи то появляются, то исчезают из списка, хотя они не выходили из приложения. При возвращении на вкладку с приложением все пользователи снова становятся активными.
Важно: в браузере Yandex Browser такого поведения не наблюдается при любых действиях с вкладками или сворачивании окна.
Основная причина проблемы заключается в том, что браузеры MS Edge и Firefox применяют ограничение (троттлинг) выполнения JavaScript таймеров в неактивных вкладках, в то время как Yandex Browser не имеет столь агрессивного ограничения. Когда вы переключаетесь на другую вкладку, браузеры замедляют выполнение setInterval и setTimeout, что приводит к искажению логики определения активных пользователей в вашем приложении.
Содержание
- Почему browsers ограничивают таймеры в неактивных вкладках
- Технические особенности троттлинга в Edge и Firefox
- Почему Yandex Browser работает иначе
- Решения для исправления проблемы
- Практические рекомендации для разработчиков
Почему browsers ограничивают таймеры в неактивных вкладках
Современные браузеры, включая MS Edge и Firefox, автоматически применяют ограничение выполнения JavaScript таймеров в неактивных вкладках для улучшения производительности системы и экономии энергии батареи [источник]. Эта функция называется “троттлинг” (throttling) и предназначена для предотвращения ненужного потребления ресурсов процессора и памяти фоновыми вкладками.
Как объясняется в документации Mozilla, “[timers such as setTimeout() are throttled in background/inactive tabs to help improve performance]” [источник]. Браузеры реализуют бюджетное ограничение для фоновых таймаутов, которое работает аналогично в современных браузерах.
В вашем случае:
- Когда вкладка неактивна, браузер замедляет выполнение
setInterval - Вместо выполнения каждые 15 секунд, как задумано, таймер может выполняться реже
- Это приводит к тому, что время последней активности в базе данных обновляется реже
- При запросе списка активных пользователей логика приложения работает с устаревшими данными
Технические особенности троттлинга в Edge и Firefox
MS Edge и “Sleeping tabs”
В MS Edge существует функция “Sleeping tabs” (спящие вкладки). Когда некоторые вкладки остаются неактивными определенный период, эта функция автоматически приостанавливает их [источник]. Это приводит к значительному ограничению выполнения JavaScript кода.
Firefox и “Tab Hibernation”
Firefox имеет функцию “Tab Hibernation” (спящий режим вкладок), которая автоматически приостанавливает вкладки, неактивные в течение определенного времени [источник]. Разработчики могут использовать событие tabs.onUpdated, чтобы определить приостановку вкладки и выполнить необходимые действия.
Конкретные ограничения таймеров
В неактивных вкладках браузеры применяют различные стратегии ограничения:
- Chrome/Edge: Таймеры могут выполняться не чаще 1 раза в секунду в фоновых вкладках [источник]
- Firefox: Ограничения также могут достигать 1 секунды для неактивных вкладок [источник]
- Бюджетная система: Браузеры используют бюджетную систему, где таймауты накапливаются и выполняются пакетами [источник]
Для вашего приложения это означает, что:
- Запись времени последней активности каждые 5 секунд может происходить реже
- Проверка активных пользователей каждые 15 секунд также может быть задержана
- В результате пользователи могут считаться неактивными преждевременно
Почему Yandex Browser работает иначе
Yandex Browser не демонстрирует такого агрессивного поведения по нескольким причинам:
Различия в реализации троттлинга
Yandex Browser, основанный на Chromium, имеет другую политику ограничения таймеров. Как отмечено в результатах поиска, “[в браузере Yandex Browser такого поведения не наблюдается при любых действиях с вкладками или сворачивании окна]” [источник].
Менее агрессивная оптимизация
В отличие от Chrome и Edge, Yandex Browser может применять менее агрессивные стратегии оптимизации энергопотребления, что позволяет JavaScript таймерам работать более предсказуемо в неактивных вкладках.
Различия в политике производительности
Каждый браузер реализует собственную политику производительности. Yandex Browser может иметь другую стратегию балансировки между энергосбережением и функциональностью веб-приложений.
Решения для исправления проблемы
1. Использование Page Visibility API
Реализуйте отслеживание видимости страницы с помощью Page Visibility API:
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
// Страница неактивна - можно приостановить обновления
pauseUserUpdates();
} else {
// Страница активна - возобновить обновления
resumeUserUpdates();
// Принудительно обновить список пользователей
updateActiveUsers();
}
});
2. Переход на Web Workers
Web Workers позволяют выполнять JavaScript код в отдельном процессе и не подвержены ограничениям вкладок браузера [источник]:
// Создание worker для фоновых операций
const worker = new Worker('user-activity-worker.js');
// Отправка данных в worker
worker.postMessage({ action: 'startTracking' });
3. Использование requestAnimationFrame
Для анимаций и периодических обновлений можно использовать requestAnimationFrame:
let lastUpdateTime = 0;
function updateLoop(timestamp) {
if (timestamp - lastUpdateTime >= 15000) {
updateActiveUsers();
lastUpdateTime = timestamp;
}
requestAnimationFrame(updateLoop);
}
requestAnimationFrame(updateLoop);
4. Переопределение таймеров
Существуют библиотеки, которые переопределяют setTimeout, setInterval, clearTimeout, clearInterval для работы в неактивных вкладках [источник]:
// Пример переопределения таймеров
const originalSetInterval = window.setInterval;
window.setInterval = function(callback, delay) {
return originalSetInterval.call(this, function() {
// Проверка видимости страницы
if (document.hidden) {
// Дополнительная логика для неактивных вкладок
}
callback.apply(this, arguments);
}, delay);
};
5. Использование серверных событий (Server-Sent Events)
Для обновления данных в реальном времени можно использовать Server-Sent Events:
const eventSource = new EventSource('/user-activity-updates');
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
updateActiveUsersList(data.activeUsers);
};
Практические рекомендации для разработчиков
Оптимизация логики приложения
- Увеличьте интервалы обновления вместо 5 и 15 секунд используйте более длительные интервалы, чтобы снизить чувствительность к троттлингу
- Реализуйте принудительное обновление при возвращении на вкладку
- Добавьте буфер времени для определения неактивных пользователей (например, 20-30 секунд вместо 15)
Мониторинг и диагностика
// Добавьте логирование для отладки
const originalSetInterval = window.setInterval;
window.setInterval = function(callback, delay, ...args) {
console.log(`setInterval called with delay: ${delay}, hidden: ${document.hidden}`);
return originalSetInterval.call(this, callback, delay, ...args);
};
Корпоративные настройки браузеров
Для корпоративной среды можно рассмотреть:
- Настройки групповой политики для ограничения троттлинга в Enterprise версиях браузеров
- Использование браузеров с предсказуемым поведением таймеров
- Обучение пользователей работе с несколькими вкладками
Источники
- Inactive Tab Throttling in browsers | aboutfrontend.blog
- Page Visibility API - Web APIs | MDN
- Chrome and Firefox throttle setTimeout/setInterval in inactive tabs | VMware Tanzu
- Heavy throttling of chained JS timers beginning in Chrome 88 | Chrome for Developers
- How can I make setInterval also work when a tab is inactive in Chrome? | Stack Overflow
- setInterval / setTimeout slows down on TAB change – Max Schmitt
- Why do browsers throttle JavaScript timers? | Read the Tea Leaves
- How to aggressively throttle background tabs in Firefox using dom.min_background_timeout_value | Super User
Заключение
Проблема “скачка” списка активных пользователей при переключении вкладках в MS Edge и Firefox вызвана агрессивным ограничением выполнения JavaScript таймеров в неактивных вкладках этих браузеров. Для решения проблемы рекомендуется:
- Реализовать отслеживание видимости страницы с помощью Page Visibility API
- Рассмотреть переход на Web Workers для фоновых операций
- Оптимировать логику приложения с учетом ограничений браузеров
- Добавить принудительное обновление данных при возвращении на вкладку
- В корпоративной среде рассмотреть возможность использования браузеров с предсказуемым поведением таймеров
Эти меры помогут обеспечить стабильную работу вашего веб-приложения независимо от поведения пользователя с вкладками браузера.