Як браузери призупиняють / змінюють Javascript, коли вкладка чи вікно не активні?


168

Передумови: я роблю кілька тестів користувальницького інтерфейсу, які потрібно виявити, люди звертають увагу чи ні. Але це питання не стосується API видимості сторінки .

Зокрема, я хотів би знати, як на мій код Javascript вплине, якщо поточна вкладка неактивна або вікно браузера не активне в різних браузерах. Я поки що викопав таке:

У мене є такі питання:

  • Чи окрім мобільних браузерів, чи настільні браузери призупиняють виконання JS, коли вкладка не активна? Коли і які браузери?
  • Які браузери зменшують setIntervalповтор? Це просто зменшено до ліміту або на відсоток? Наприклад, якщо я повторюю 10 мс проти повторення 5000 м, як це вплине на кожного?
  • Чи відбуваються ці зміни, якщо вікно не фокусується, а не лише вкладка? (Я думаю, що це буде важче виявити, оскільки це вимагає API OS.)
  • Чи є інші ефекти, які не спостерігалися б на активній вкладці? Чи могли вони зіпсувати речі, які б інакше були виконані правильно (тобто згадані вище тести на Жасмін)?

Якщо вони призупинені, такі сайти, як Facebook, не отримуватимуть жодних повідомлень чату на вкладках фону.
Йосип

1
Так, немає пауз, але я пам’ятаю, що читав, що setInterval/ setTimeoutраз під 1000мс змінюється на 1000м, коли вкладка / вікно розмивається
Ян

19
@ProfPickle Вебмайстри? Дійсно? Це питання програмування JS.
Ендрю Мао

1
@lan setInterval/ setTimeoutчас під 1000ms змінюється на 1000ms, коли вкладка / вікно розмивається. Не ясно, що ви намагалися передати
Amol M Kulkarni

4
+1 Відмінне запитання. Було б добре бачити співставлення поведінки браузера, оскільки я вважаю, що затискача поведінки, коли вкладки не активні, не є частиною будь-якого стандарту.
UpTheCreek

Відповіді:


190

Тест перший

Я написав тест спеціально для цієї мети:
Розподіл частоти кадрів: setInterval vs requestAnimationFrame

Примітка. Цей тест досить інтенсивний процесор. requestAnimationFrameне підтримується IE 9- та Opera 12-.

Тест реєструє фактичний час, який потрібно для роботи a setIntervalі requestAnimationFrameв різних браузерах, і дає результати у вигляді розподілу. Ви можете змінити кількість мілісекунд, setIntervalщоб побачити, як воно працює в різних налаштуваннях. setTimeoutпрацює аналогічно setIntervalвідносно затримок. requestAnimationFrameзазвичай за замовчуванням до 60 кадрів в секунду залежно від браузера. Щоб побачити, що відбувається, коли ви переходите на іншу вкладку або маєте неактивне вікно, просто відкрийте сторінку, перейдіть на іншу вкладку і почекайте деякий час. Він буде продовжувати фіксувати фактичний час, необхідний для виконання цих функцій, на неактивній вкладці.

Тест два

Ще один спосіб перевірити це, щоб увійти в мітку часу неодноразово з setIntervalі requestAnimationFrameпереглянути його в окремому консолі. Ви можете бачити, як часто воно оновлюється (або якщо воно коли-небудь оновлюється), коли ви робите вкладку чи вікно неактивними.

Результати

Chrome
Chrome обмежує мінімальний інтервал setIntervalприблизно до 1000 мс, коли вкладка неактивна. Якщо інтервал перевищує 1000 мс, він буде працювати на зазначеному інтервалі. Не має значення, якщо вікно не фокусується, інтервал обмежується лише при переході на іншу вкладку. requestAnimationFrameпризупиняється, коли вкладка неактивна.

// Provides control over the minimum timer interval for background tabs.
const double kBackgroundTabTimerInterval = 1.0;

https://codereview.chromium.org/6546021/patch/1001/2001

Firefox
Подібно до Chrome, Firefox обмежує мінімальний інтервал setIntervalприблизно до 1000 мс, коли вкладка (не вікно) неактивна. Однак requestAnimationFrameзапускається експоненціально повільніше, коли вкладка неактивна, кожен кадр займає значення 1s, 2s, 4s, 8s тощо.

// The default shortest interval/timeout we permit
#define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
#define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms

https://hg.mozilla.org/releases/mozilla-release/file/0bf1cadfb004/dom/base/nsGlobalWindow.cpp#l296

Internet Explorer
IE не обмежує затримку, setIntervalколи вкладка неактивна, але робить паузу requestAnimationFrameна неактивних вкладках. Не має значення, вікно не в фокусі чи ні.

Край,
починаючи з краю 14, setIntervalмає обмеження в 1000 м на неактивних вкладках. requestAnimationFrameзавжди призупинено на неактивних вкладках.

Safari
Так само, як Chrome, Safari обмежується setIntervalв 1000 м, коли вкладка неактивна. requestAnimationFrameтакож призупинено.

Opera
З моменту створення двигуна Webkit, Opera проявляє таку ж поведінку, як і Chrome. setIntervalобмежується на 1000 мс і requestAnimationFrameпризупиняється, коли вкладка неактивна.

Підсумок

Повторення інтервалів для неактивних вкладок:

           setInterval      requestAnimationFrame 
Chrome
9- не впливає, не підтримується
10 не вплинуло на паузу
11+> = 1000 мс призупинено

Firefox
3- не постраждало, не підтримується
4 не зачеплені 1с
5+> = 1000 мс 2 n s (n = кількість кадрів з моменту бездіяльності)

IE
9- не впливає, не підтримується
10+ не впливають на паузу

Край
13- не вплинуло на паузу
14+> = 1000 мс призупинено

Сафарі
5- не постраждали, не підтримуються
6 не вплинуло на паузу
7+> = 1000 мс призупинено

Опера
12- не впливає, не підтримується
15+> = 1000 мс призупинено

Чудова відповідь. Будь-які інші відомі відмінності для функцій, відмінних від setIntervalта requestAnimationFrame?
Ендрю Мао

1
@AndrewMao Не те, про що я знаю. Я натрапив на це питання , коли я працював в бібліотеці , щоб надійно виявити , якщо JS знову включити з setIntervalі requestAnimationFrame. Що я знаю про те, що вона setTimeoutповодиться аналогічно тому setInterval, що вони мають однаковий мінімальний інтервал фону у Firefox та Chrome, а також відсутність явного обмеження в інших браузерах.
Антоній

2
Мінімальне значення Firefox setInterval, очевидно, може бути змінено, відкривши URL-адресу about:configв браузері і змінивши dom.min_background_timeout_valueзначення на щось інше, ніж 1000.
Jonas Berlin,

Чи можу я використовувати це для перезавантаження сторінки кожні 5 секунд, коли браузер зведений до мінімуму ?, ось моє питання.
shaijut

1
Зауважте, що хром не призупиняє / не зменшує швидкість, з якою requestAnimationFrameвикликається, якщо користувач просто перемикає програму (Alt + Tab з Chrome). Поки вкладка активна в Chrome, "частота кадрів" є більш-менш постійною.
Марк

11

Що я зауважив: на неактивних вкладках у Chrome усі ваші setTimeout(повинні бути однакові setInterval) очікування менше 1000 м округлюються до 1000 мс . Я думаю, що більш тривалі очікування не змінюються.

Здається, це поведінка з Chrome 11 та Firefox 5.0 : https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout#Inactive_tabs

Крім того, я не думаю, що він веде себе так, коли все вікно неактивне (але це здається досить простим).


1
jQuery focusі blurподії, схоже, виявляють як перемикачі вкладок, так і вікон, тому це може працювати обома способами. Але мені цікаво, як вікно виявляє, чи воно насправді видно чи ні.
Ендрю Мао

2
Насправді він не має зв'язку з jQuery або Javascript, оскільки це внутрішня реалізація браузера.

Чи можете ви підтвердити це зараз наприкінці 2016 року?
vsync

0

Більш нова відповідь на доповнення до цього: на хромовому 78.0.3904.108 я помічаю, що всі ці тайм-аути (не лише ті, що не перевищують 1000 мс) забирають трохи більше часу, ніж очікувалося, коли я переходжу на іншу вкладку, а потім повертаюся назад. Поведінка, яку я бачу, більш правильно описана як "Усі очікування на неактивних вкладках можуть бути затримані на деяку додаткову суму, максимум до 1000 мс".:

let timeouts = [ 500, 1000, 2000, 3000, 10000 ];

let minExcess = document.getElementsByClassName('minExcess')[0];

timeouts.forEach(ms => {
  let elem = document.getElementsByClassName(`t${ms}`)[0];
  let cnt = 0;
  
  let lastMs = +new Date();
  let f = () => {
    let curMs = +new Date();
    let disp = document.createElement('p');
    let net = curMs - lastMs;
    lastMs = curMs;
        
    setTimeout(f, ms);
    if (minExcess.value && (net - ms) < parseInt(minExcess.value)) return;
    
    disp.innerText = `${net},`;
    elem.appendChild(disp);
    if (++cnt > 10) elem.firstElementChild.remove();
    
  };
  setTimeout(f, ms);
  
});
body { font-size: 80%; }
div {
  max-height: 80px;
  overflow-x: auto;
  background-color: rgba(0, 0, 0, 0.1);
  margin-bottom: 2px;
  white-space: nowrap;
}
p { margin: 0; }
div > p {
  margin: 0;
  display: inline-block;
  vertical-align: top;
  margin-right: 2px;
}
input { margin: 0 0 10px 0; }
.t500:before { display: block; content: '500ms'; font-weight: bold; }
.t1000:before { display: block; content: '1000ms'; font-weight: bold; }
.t2000:before { display: block; content: '2000ms'; font-weight: bold; }
.t3000:before { display: block; content: '3000ms'; font-weight: bold; }
.t10000:before { display: block; content: '10000ms'; font-weight: bold; }
<p>Ignore any values delayed by less than this amount:</p>
<input type="text" class="minExcess" value="200" pattern="^[0-9]*$"/>
<div class="timeout t500"></div>
<div class="timeout t1000"></div>
<div class="timeout t2000"></div>
<div class="timeout t3000"></div>
<div class="timeout t10000"></div>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.