Mam setInterval
działający fragment kodu 30 razy na sekundę. Działa to świetnie, jednak gdy wybiorę inną kartę (aby karta z moim kodem stała się nieaktywna),setInterval
jakiegoś powodu ustawia się ją w stan bezczynności.
Zrobiłem ten uproszczony przypadek testowy ( http://jsfiddle.net/7f6DX/3/ ):
var $div = $('div');
var a = 0;
setInterval(function() {
a++;
$div.css("left", a)
}, 1000 / 30);
Jeśli uruchomisz ten kod, a następnie przełączysz się na inną kartę, poczekaj kilka sekund i wróć, animacja będzie kontynuowana w momencie, w którym przełączyłeś się na inną kartę. Tak więc animacja nie jest uruchamiana 30 razy na sekundę w przypadku, gdy karta jest nieaktywna. Można to potwierdzić, licząc liczbę razysetInterval
funkcji w każdej sekundzie - nie będzie to 30, ale tylko 1 lub 2, jeśli karta jest nieaktywna.
Wydaje mi się, że odbywa się to zgodnie z projektem, aby poprawić wydajność, ale czy jest jakiś sposób na wyłączenie tego zachowania? W moim scenariuszu jest to faktycznie wada.
źródło
Date
obiektem, aby naprawdę zobaczyć, co minęło.Date
. Tak więc, gdy interwały nie uruchamiają się szybko (z tego lub innych powodów) animacja staje się bardziej gwałtowna, a nie wolniejsza.Odpowiedzi:
W większości przeglądarek nieaktywne karty mają niski priorytet wykonywania, co może mieć wpływ na liczniki JavaScript.
Jeśli wartości przejścia zostały obliczone przy użyciu czasu rzeczywistego między ramkami zamiast ustalonych przyrostów w każdym interwale, można nie tylko obejść ten problem, ale także uzyskać płynniejszą animację za pomocą requestAnimationFrame, ponieważ może uzyskać do 60 kl./s, jeśli procesor nie jest bardzo zajęty.
Oto waniliowy przykład JavaScript animowanego przejścia właściwości za pomocą
requestAnimationFrame
:Do zadań w tle (niezwiązanych z interfejsem użytkownika)
@UpTheCreek komentarz:
Jeśli masz zadania w tle, które muszą być precyzyjnie wykonywane w określonych odstępach czasu, możesz użyć HTML5 Web Workers . Spójrz na odpowiedź Möhre poniżejWięcej informacji ...
„Animacje” CSS vs JS
Tego problemu i wielu innych można uniknąć, stosując przejścia / animacje CSS zamiast animacji opartych na JavaScript, co powoduje znaczne obciążenie. Polecam tę wtyczkę jQuery, która pozwala czerpać korzyści z przejść CSS, podobnie jak
animate()
metody.źródło
before = now;
aby uzyskać upływ czasu od początku zamiast końca poprzedniego wywołania. Tego zazwyczaj chcesz animować. Tak jak jest teraz, jeśli wykonanie funkcji interwału zajmuje 15 ms,elapsedTime
da kolejne 35 ms (zamiast 50 ms, co jest interwałem) przy następnym wywołaniu (gdy karta jest aktywna).Mam ten sam problem z wygaszaniem dźwięku i odtwarzaczem HTML5. Utknął, gdy karta stała się nieaktywna. Dowiedziałem się więc, że WebWorker może używać interwałów / limitów czasowych bez ograniczeń. Używam go do publikowania „tyknięć” w głównym javascript.
Kod Webworkers:
Główny Javascript:
źródło
Istnieje rozwiązanie do korzystania z pracowników sieci Web (jak wspomniano wcześniej), ponieważ działają one w osobnym procesie i nie są spowalniane
Napisałem mały skrypt, którego można używać bez zmian w kodzie - po prostu przesłania funkcje setTimeout, clearTimeout, setInterval, clearInterval.
Po prostu dołącz go przed całym kodem.
więcej informacji tutaj
źródło
Po prostu zrób to:
Nieaktywne karty przeglądarki buforują niektóre funkcje
setInterval
lubsetTimeout
.stop(true,true)
zatrzyma wszystkie buforowane zdarzenia i natychmiast wykona tylko ostatnią animację.window.setTimeout()
Metoda klejenia teraz wysłać nie więcej niż jeden czas oczekiwania na sekundę w nieaktywnych kart. Ponadto ogranicza teraz zagnieżdżone limity czasu do najmniejszej wartości dopuszczalnej przez specyfikację HTML5: 4 ms (zamiast 10 ms, przy której był zaciskany).źródło
Myślę, że najlepiej rozumiem ten problem w tym przykładzie: http://jsfiddle.net/TAHDb/
Robię tutaj prostą rzecz:
Zachowaj odstęp 1 sekundy i za każdym razem ukryj pierwszy zakres, przesuń go do ostatniego i pokaż drugi zakres.
Jeśli zostaniesz na stronie, działa tak, jak powinno. Ale jeśli ukryjesz kartę na kilka sekund, po powrocie zobaczysz zużyty przedmiot.
To tak, jakby wszystkie zdarzenia, które nie wystąpiły w czasie, gdy byłeś nieaktywny, pojawią się za jednym razem. więc przez kilka sekund otrzymacie X wydarzeń. są tak szybkie, że można zobaczyć wszystkie 6 zakresów jednocześnie.
Dzięki temu chrom tylko opóźnia wydarzenia, więc kiedy wrócisz, wszystkie wydarzenia wystąpią, ale wszystkie naraz ...
Praktyczne zastosowanie to ta okazja do prostego pokazu slajdów. Wyobraź sobie, że liczby są obrazami, a jeśli użytkownik pozostanie z ukrytą kartą, gdy wróci, zobaczy wszystkie pływające obrazy, Całkowicie zmieszane.
Aby to naprawić, użyj stop (true, true), jak powiedział pimvdb. Spowoduje to wyczyszczenie kolejki zdarzeń.
źródło
requestAnimationFrame
jQuery. Z powodu niektórych dziwactw, jakie miał (jak ten), usunęli go. W 1.7 nie widzisz tego zachowania. jsfiddle.net/TAHDb/1 . Ponieważ interwał jest raz na sekundę, tak naprawdę nie wpływa to na opublikowany przeze mnie problem, ponieważ maksimum dla nieaktywnych kart wynosi również raz na sekundę - więc to nie ma znaczenia.Dla mnie nie jest ważne, aby odtwarzać dźwięk w tle, tak jak dla innych tutaj, moim problemem było to, że miałem kilka animacji i działały jak szalone, gdy byłeś w innych kartach i wracałeś do nich. Moim rozwiązaniem było umieszczenie tych animacji wewnątrz, jeśli to uniemożliwia nieaktywną kartę :
dzięki temu moja animacja działała tylko przy aktywnej zakładce. Mam nadzieję, że to pomoże komuś w mojej sprawie.
źródło
setInterval(() => !document.hidden && myfunc(), 1000)
i działa idealnieZarówno
setInterval
irequestAnimationFrame
nie działają, gdy karta jest nieaktywna lub pracy, ale nie w odpowiednich okresach. Rozwiązaniem jest użycie innego źródła zdarzeń czasowych. Na przykład gniazda sieciowe lub procesy sieciowe są dwoma źródłami zdarzeń, które działają dobrze, gdy karta jest nieaktywna. Nie trzeba więc przenosić całego kodu do pracownika sieci, wystarczy użyć pracownika jako źródła zdarzenia czasu:.
jsfiddle link do tej próbki.
źródło
Będąc pod silnym wpływem biblioteki Rusłana Tushova, stworzyłem własną małą bibliotekę . Po prostu dodaj skrypt do
<head>
i będzie łatałsetInterval
isetTimeout
tymi, które go używająWebWorker
.źródło
Odtwarzanie pliku audio zapewnia na razie pełną obsługę JavaScript w tle
Dla mnie było to najprostsze i najmniej inwazyjne rozwiązanie - poza odtwarzaniem słabego / prawie pustego dźwięku, nie ma innych potencjalnych efektów ubocznych
Szczegóły znajdziesz tutaj: https://stackoverflow.com/a/51191818/914546
(Z innych odpowiedzi wynika, że niektórzy ludzie używają różnych właściwości tagu audio, zastanawiam się, czy można użyć tagu audio w celu uzyskania pełnej wydajności, bez faktycznego odtwarzania)
źródło
Uwaga: to rozwiązanie nie jest odpowiednie, jeśli podoba Ci się, że Twój interwał działa w tle, na przykład podczas odtwarzania dźwięku lub ... ale jeśli nie rozumiesz na przykład, że animacja nie działa poprawnie po powrocie na stronę (kartę) dobre rozwiązanie.
Istnieje wiele sposobów na osiągnięcie tego celu, być może „WebWorkers” jest najbardziej standardowy, ale na pewno nie jest to najłatwiejszy i najbardziej przydatny, zwłaszcza jeśli nie masz wystarczająco dużo czasu, więc możesz spróbować w ten sposób:
►PODSTAWOWA KONCEPCJA:
1- zbuduj nazwę interwału (lub animacji) i ustaw interwał (animację), aby był uruchamiany, gdy użytkownik po raz pierwszy otworzy stronę:
var interval_id = setInterval(your_func, 3000);
2 obok
$(window).focus(function() {});
i$(window).blur(function() {});
możeszclearInterval(interval_id)
za każdym razem dezaktywować przeglądarkę (zakładkę) i ponownie uruchomić interwał (animację) za każdym razem, gdy przeglądarka (zakładka) będzie ponownie aktywowana przezinterval_id = setInterval();
►KOD PRZYKŁADOWY:
źródło
To dość stare pytanie, ale napotkałem ten sam problem.
Jeśli korzystasz z sieci na Chrome, możesz przeczytać ten wpis Karty w tle w Chrome 57 .
Zasadniczo licznik czasu może działać, jeśli nie zabraknie mu budżetu czasu.
Zużycie budżetu opiera się na zużyciu czasu procesora przez zadanie wewnątrz timera.
W oparciu o mój scenariusz rysuję wideo na płótnie i transportuję do WebRTC.
Połączenie wideo webrtc aktualizuje się, nawet karta jest nieaktywna.
Musisz jednak użyć
setInterval
zamiastrequestAnimationFrame
.nie jest to jednak zalecane do renderowania interfejsu użytkownika.
Lepiej byłoby słuchać
visibilityChange
zdarzenia i odpowiednio zmieniać mechanizm renderowania.Poza tym możesz spróbować @ kaan-soral i powinno działać w oparciu o dokumentację.
źródło
Oto moje szorstkie rozwiązanie
źródło
postMessageHandler
Powołuje własną imprezę jest magazynowe, tym samym mając nieskończoną pętlę, która nie blokuje UI. Podczas gdy nieskończenie zapętla się, przy każdej obsłudze zdarzeń sprawdza, czy jest dostępna funkcja limitu czasu lub funkcji interwału.Byłem w stanie wywołać moją funkcję oddzwaniania co najmniej 250 ms za pomocą znacznika audio i obsługi jego zdarzenia ontimeupdate. Nazywa się to 3-4 razy na sekundę. Jego opóźnienie jest lepsze niż jedna sekunda
źródło