Chrome: тайм-аут / інтервал призупинено у вкладках фону?


130

Я перевіряв точність setTimeoutвикористання цього тесту . Тепер я помітив, що (як і очікувалося) setTimeoutне дуже точний, але для більшості приладів не сильно неточний. Тепер, якщо я запускаю тест у Chrome і дозволю його виконувати на вкладці тла (так, перехід на іншу вкладку і перегляд там), повернення до тесту та перевірку результатів (якщо тест закінчений), вони кардинально змінюються. Схоже, час очікування працює набагато повільніше. Випробувано в FF4 або IE9 цього не сталося.

Так виглядає, що Chrome призупиняє або принаймні уповільнює виконання javascript на вкладці, яка не фокусується. Не вдалося знайти багато в мережі з цього питання. Це означатиме, що ми не можемо виконувати фонові завдання, як, наприклад, періодично перевіряти на сервері за допомогою дзвінків XHR і setInterval(підозрюю, що бачу таку саму поведінку setInterval, напишу тест, якщо час зі мною).

Хтось із цим стикався? Чи може бути вирішення цієї зупинки / уповільнення? Ви б назвали це помилкою, і чи потрібно я її подавати як таку?


Цікаво! Чи можете ви сказати, чи Chrome призупиняє та поновлює таймер або перезапускає його, як тільки ви знову відкриєте вкладку? Або поведінка випадкова? Чи може це мати щось спільне з тим, що Chrome запускає вкладки в незалежних процесах?
HyderA

@gAMBOOKa: подивись відповідь @ pimvdb. Ймовірно, це повільне уповільнення до максимуму раз на секунду.
KooiInc

Через 4 роки і ця проблема все ще існує. У мене є setTimeOut для divs з a transition, тому не всі діви переходять одночасно, але насправді через 15 мс після іншого, створюючи деякий ефект кочення. Коли я переходжу на іншу вкладку і через деякий час повертаюсь, всі діви переходять одночасно і setTimeOutцілком ігнорується. Це не є великою проблемою для мого проекту, але це дивне і небажане доповнення.
Рвервурт

Для нашої анімації, яка називала setTimeout послідовно, рішенням для нас було лише переконатися, що ми пам'ятаємо ручку / ідентифікатор таймера (він повертається з setTimeout), і перед тим, як встановити новий таймер, ми спочатку викликаємо clearTimeout, якщо у нас є дістали ручку. У нашому випадку це означає, що коли ви повернетесь до вкладки, може виникнути деяка початкова вірогідність щодо того, яка анімація відтворюється, але вона досить швидко розбирається, і звичайна анімація поновлюється. Ми думали, що це спочатку проблема з кодом.
Дія Дан

Відповіді:


88

Нещодавно я запитав про це, і це поведінка в дизайні. Якщо вкладка неактивна, функція викликається лише максимум раз на секунду. Ось зміна коду .

Можливо, це допоможе: Як я можу зробити так, щоб setInterval також працював, коли в Chrome не працює вкладка?

TL; DR: використовувати веб-працівників .


3
дякую, я мав би подивитися на "неактивну вкладку". Іноді не бути носієм англійської мови іноді є гандикапом.
KooiInc

1
@Kooilnc: Немає проблем :) Я також не є носієм англійської мови.
pimvdb

22

Є рішення використовувати Web Workers, оскільки вони працюють в окремому процесі і не сповільнюються

Я написав крихітний сценарій, який можна використовувати без змін у вашому коді - він просто перекриває функції setTimeout, clearTimeout, setInterval, clearInterval

Просто включіть його перед усім кодом

http://github.com/turuslan/HackTimer


7
Це добре і все, але пам'ятайте, що: 1. Робітники не мають доступу до DOM, 2. Робітники виконуються лише коли вони є у файлі самостійно. Це не є заміною для випадання setTimeout у багатьох випадках.
Привид

1
Ви маєте рацію, але деякі сучасні браузери дозволяють використовувати працівників без власних файлів, використовуючи Blobs ( html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers )
Руслан Тушов

1
Навіть при цьому веб-працівникам бракує багато функціоналу (а саме DOM), що дозволяє їм бути безпечною заміною setTimeout та co.
Привид

А як щодо коду, який повинен працювати в передній частині, наприклад, важких завдань обробки графіки, які ми хотіли б виконати, поки ми робимо інші речі?
Майкл

Ну, ви можете створити Workers, службовців та використовувати API полотна за допомогою URL-адреси даних. new Worker('data:text/javascript,(' + function myWorkerCode () { /*...*/ } + '()'). Це також приємний спосіб перевірити, чи є у вас підтримка виразів імпорту:try { eval('import("data:text/javascript,void 0")') } catch (e) { /* no support! */ }
Fábio Santos

9

Відтворення ~ порожнього звуку змушує браузер зберігати продуктивність - я виявив це, прочитавши цей коментар: Як змусити JavaScript працювати з нормальною швидкістю в Chrome, навіть коли вкладка не активна?

Мені потрібна необмежена продуктивність на вимогу для гри в браузері, що використовує WebSockets, тож з досвіду я знаю, що використання WebSockets не забезпечує необмежену продуктивність, але за допомогою тестів, відтворення аудіофайлу, здається, забезпечує це

Ось дві порожні аудіо цикли, які я створив для цієї мети, ви можете використовувати їх вільно, комерційно: http://adventure.land/sounds/loops/empty_loop_for_js_performance.ogg http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav

(Вони включають шум -58db, -60db не працює)

Я відтворюю їх на запит користувачів, з Howler.js: https://github.com/goldfire/howler.js

function performance_trick()
{
    if(sounds.empty) return sounds.empty.play();
    sounds.empty = new Howl({
        src: ['/sounds/loops/empty_loop_for_js_performance.ogg','/sounds/loops/empty_loop_for_js_performance.wav'],
        volume:0.5,
        autoplay: true, loop: true,
    });
}

Сумно, що не існує вбудованого методу для ввімкнення / вимкнення повної продуктивності JavaScript, але, криптовалюти можуть викрасти всі ваші обчислювальні потоки за допомогою Web Workers без будь-якого підказу: |


Дякую, 58db дуже важкий для навушників тхо, але приглушення сайту вирішує цю проблему
Kaan Soral

1

Я випустив пакет npm для робочого інтервалу, який встановлює реалізацію Interterval та clearInterval за допомогою Web-Workers для продовження та роботи на неактивних вкладках для Chrome, Firefox та IE.

Більшість сучасних браузерів (Chrome, Firefox та IE), інтервали (таймери вікон) затискаються для запуску не частіше одного разу на секунду на неактивних вкладках.

Ви можете знайти більше інформації на

https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Timeouts_and_intervals


0

Я оновив своє ядро ​​jQuery до 1.9.1, і це вирішило інтервальну невідповідність в неактивних вкладках. Я спробував би це спершу, а потім вивчити інші варіанти заміни коду.


з якої версії ви оновили? У мене виникли деякі проблеми з тайм-аутом (слайдери галереї) з версією ~ 1.6
dmi3y

0

ось моє рішення, яке отримує поточну мілісекунду, і порівнює його з мілісекундою, яку створила функція. за інтервал, він буде оновлювати мілісекунд, коли він виконує функцію. ви також можете захопити інтервал / час очікування за ідентифікатором.

<script>

var nowMillisTimeout = [];
var timeout = [];
var nowMillisInterval = [];
var interval = [];

function getCurrentMillis(){
    var d = new Date();
    var now = d.getHours()+""+d.getMinutes()+""+d.getSeconds()+""+d.getMilliseconds();
    return now;
}

function setAccurateTimeout(callbackfunction, millis, id=0){
    nowMillisTimeout[id] = getCurrentMillis();
    timeout[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisTimeout[id] + +millis)){callbackfunction.call(); clearInterval(timeout[id]);} }, 10);
}

function setAccurateInterval(callbackfunction, millis, id=0){
    nowMillisInterval[id] = getCurrentMillis();
    interval[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisInterval[id] + +millis)){callbackfunction.call(); nowMillisInterval[id] = getCurrentMillis();} }, 10);
}

//usage
setAccurateTimeout(function(){ console.log('test timeout'); }, 1000, 1);

setAccurateInterval(function(){ console.log('test interval'); }, 1000, 1);

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