Другое

Почему список активных пользователей прыгает при переключении вкладок

Узнайте причины скачков списка активных пользователей в Edge и Firefox при переключении вкладок и как это исправить.

Почему при переключении между вкладками в браузерах MS Edge и Firefox список активных пользователей в веб-приложении ‘скачет’?

У меня есть веб-приложение, работающее в корпоративной доменной сети. В приложении есть раздел ‘Активные пользователи’, который обновляется каждые 15 секунд. Система работает следующим образом:

  1. Каждые 5 секунд в базу данных записывается текущее время как время последней активности пользователя
  2. Каждые 15 секунд приложение запрашивает список активных пользователей, сравнивая текущее время со временем последней активности
  3. Если разница во времени превышает 15 секунд, пользователь считается неактивным и не отображается в списке

Проблема: при переключении на другие вкладки в браузерах MS Edge и Firefox список активных пользователей начинает ‘прыгать’ - пользователи то появляются, то исчезают из списка, хотя они не выходили из приложения. При возвращении на вкладку с приложением все пользователи снова становятся активными.

Важно: в браузере Yandex Browser такого поведения не наблюдается при любых действиях с вкладками или сворачивании окна.

Основная причина проблемы заключается в том, что браузеры MS Edge и Firefox применяют ограничение (троттлинг) выполнения JavaScript таймеров в неактивных вкладках, в то время как Yandex Browser не имеет столь агрессивного ограничения. Когда вы переключаетесь на другую вкладку, браузеры замедляют выполнение setInterval и setTimeout, что приводит к искажению логики определения активных пользователей в вашем приложении.


Содержание


Почему 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:

javascript
document.addEventListener('visibilitychange', function() {
    if (document.hidden) {
        // Страница неактивна - можно приостановить обновления
        pauseUserUpdates();
    } else {
        // Страница активна - возобновить обновления
        resumeUserUpdates();
        // Принудительно обновить список пользователей
        updateActiveUsers();
    }
});

2. Переход на Web Workers

Web Workers позволяют выполнять JavaScript код в отдельном процессе и не подвержены ограничениям вкладок браузера [источник]:

javascript
// Создание worker для фоновых операций
const worker = new Worker('user-activity-worker.js');

// Отправка данных в worker
worker.postMessage({ action: 'startTracking' });

3. Использование requestAnimationFrame

Для анимаций и периодических обновлений можно использовать requestAnimationFrame:

javascript
let lastUpdateTime = 0;
function updateLoop(timestamp) {
    if (timestamp - lastUpdateTime >= 15000) {
        updateActiveUsers();
        lastUpdateTime = timestamp;
    }
    requestAnimationFrame(updateLoop);
}
requestAnimationFrame(updateLoop);

4. Переопределение таймеров

Существуют библиотеки, которые переопределяют setTimeout, setInterval, clearTimeout, clearInterval для работы в неактивных вкладках [источник]:

javascript
// Пример переопределения таймеров
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:

javascript
const eventSource = new EventSource('/user-activity-updates');
eventSource.onmessage = function(event) {
    const data = JSON.parse(event.data);
    updateActiveUsersList(data.activeUsers);
};

Практические рекомендации для разработчиков

Оптимизация логики приложения

  1. Увеличьте интервалы обновления вместо 5 и 15 секунд используйте более длительные интервалы, чтобы снизить чувствительность к троттлингу
  2. Реализуйте принудительное обновление при возвращении на вкладку
  3. Добавьте буфер времени для определения неактивных пользователей (например, 20-30 секунд вместо 15)

Мониторинг и диагностика

javascript
// Добавьте логирование для отладки
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 версиях браузеров
  • Использование браузеров с предсказуемым поведением таймеров
  • Обучение пользователей работе с несколькими вкладками

Источники

  1. Inactive Tab Throttling in browsers | aboutfrontend.blog
  2. Page Visibility API - Web APIs | MDN
  3. Chrome and Firefox throttle setTimeout/setInterval in inactive tabs | VMware Tanzu
  4. Heavy throttling of chained JS timers beginning in Chrome 88 | Chrome for Developers
  5. How can I make setInterval also work when a tab is inactive in Chrome? | Stack Overflow
  6. setInterval / setTimeout slows down on TAB change – Max Schmitt
  7. Why do browsers throttle JavaScript timers? | Read the Tea Leaves
  8. How to aggressively throttle background tabs in Firefox using dom.min_background_timeout_value | Super User

Заключение

Проблема “скачка” списка активных пользователей при переключении вкладках в MS Edge и Firefox вызвана агрессивным ограничением выполнения JavaScript таймеров в неактивных вкладках этих браузеров. Для решения проблемы рекомендуется:

  1. Реализовать отслеживание видимости страницы с помощью Page Visibility API
  2. Рассмотреть переход на Web Workers для фоновых операций
  3. Оптимировать логику приложения с учетом ограничений браузеров
  4. Добавить принудительное обновление данных при возвращении на вкладку
  5. В корпоративной среде рассмотреть возможность использования браузеров с предсказуемым поведением таймеров

Эти меры помогут обеспечить стабильную работу вашего веб-приложения независимо от поведения пользователя с вкладками браузера.

Авторы
Проверено модерацией
Модерация