Chrome: тайм-ауты / интервал приостановлены в фоновых вкладках? - PullRequest
115 голосов
/ 17 мая 2011

Я проверял точность setTimeout, используя этот тест .Теперь я заметил, что (как и ожидалось) setTimeout не очень точен, но для большинства приборов не очень точен.Теперь, если я запускаю тест в Chrome и позволяю ему запускаться на фоновой вкладке (то есть, переключаясь на другую вкладку и просматривая ее там), возвращаясь к тесту и просматривая результаты (если тест завершен), они кардинально меняются.Похоже, тайм-ауты были намного медленнее.Протестировано в FF4 или IE9 этого не произошло.

Таким образом, похоже, что Chrome приостанавливает или, по крайней мере, замедляет выполнение JavaScript на вкладке, которая не имеет фокуса.Не могу найти много в сети на эту тему.Это означало бы, что мы не можем запускать фоновые задачи, такие как, например, периодическая проверка на сервере с использованием вызовов XHR и setInterval (я подозреваю, что подобное поведение будет наблюдаться для setInterval, напишет тест, если время у меня).

Кто-нибудь сталкивался с этим?Будет ли обходной путь для этой приостановки / замедления?Вы бы назвали это ошибкой, и я должен подать ее как таковую?

Ответы [ 6 ]

77 голосов
/ 17 мая 2011

Я недавно спрашивал об этом, и это поведение по дизайну. Когда вкладка неактивна, вызывается только максимум один раз в секунду. Вот код изменения .

Возможно, это поможет: Как заставить setInterval также работать, когда вкладка неактивна в Chrome?

TL; DR: использование Web Workers .

21 голосов
/ 29 июня 2015

Существует решение использовать Web Workers, потому что они работают в отдельном процессе и не замедляются

Я написал крошечный скрипт, который можно использовать без изменений в вашем коде - он просто переопределяет функции setTimeout, clearTimeout, setInterval, clearInterval

Просто включите его перед всем вашим кодом

http://github.com/turuslan/HackTimer

4 голосов
/ 05 июля 2018

Воспроизведение пустого звука заставляет браузер сохранять производительность - я обнаружил это после прочтения этого комментария: Как заставить 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

(они включают шум -58 дБ, не работает -60 дБ)

Я играю их по требованию пользователя с помощью 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 без какого-либо запроса: |

1 голос
/ 13 декабря 2017

Я выпустил рабочий интервал npm, в котором реализована реализация setInterval и clearInterval с использованием веб-работников для поддержки и работы на неактивных вкладках для 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

1 голос
/ 11 июля 2013

Я обновил свое ядро ​​jQuery до 1.9.1, и это решило расхождение интервала в неактивных вкладках.Сначала я попробую, а затем загляну в другие варианты переопределения кода.

0 голосов
/ 05 июня 2019

вот мое решение, которое получает текущую миллисекунду и сравнивает ее с миллисекундой, в которую была создана функция. для интервала будет обновляться миллисекунда при запуске функции. Вы также можете получить интервал / тайм-аут по идентификатору.

<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>
...