Chrome: batas waktu / interval ditangguhkan di tab latar belakang?

130

Saya sedang menguji akurasi setTimeoutmenggunakan tes ini . Sekarang saya perhatikan bahwa (seperti yang diharapkan) setTimeouttidak terlalu akurat tetapi untuk sebagian besar peralatan tidak secara dramatis tidak akurat. Sekarang jika saya menjalankan tes di Chrome dan membiarkannya berjalan di tab latar belakang (jadi, beralih ke tab lain dan jelajahi di sana), kembali ke tes dan memeriksa hasil te (jika tes selesai) mereka berubah secara dramatis. Sepertinya batas waktu berjalan lebih lambat. Diuji dalam FF4 atau IE9 ini tidak terjadi.

Jadi sepertinya Chrome menangguhkan atau setidaknya memperlambat eksekusi javascript di tab yang tidak memiliki fokus. Tidak dapat menemukan banyak di internet tentang hal ini. Itu berarti bahwa kita tidak dapat menjalankan tugas latar belakang, seperti misalnya memeriksa secara berkala pada server menggunakan panggilan XHR dan setInterval(saya curiga melihat perilaku yang sama setInterval, akan menulis tes jika waktunya bersama saya).

Adakah yang mengalami ini? Apakah akan ada solusi untuk suspensi ini / memperlambat? Apakah Anda menyebutnya bug dan haruskah saya mengajukannya?

KooiInc
sumber
Menarik! Bisakah Anda tahu apakah Chrome menjeda dan melanjutkan timer atau memulai ulang, setelah Anda mengakses kembali tab? Atau apakah tingkah lakunya acak? Mungkinkah ada hubungannya dengan fakta bahwa Chrome menjalankan tab dalam proses independen?
HyderA
@gAMBOOKa: lihat jawaban @ pimvdb. Kemungkinan memperlambat hingga maksimum sekali per detik.
KooiInc
4 tahun kemudian dan masalah ini masih ada. Saya memiliki setTimeOut untuk div dengan transition, jadi tidak semua transisi divs pada saat yang sama, tetapi sebenarnya 15 ms setelah satu sama lain, menciptakan beberapa efek bergulir. Ketika saya pergi ke tab lain dan kembali setelah beberapa saat, semua transisi divs pada saat yang sama dan setTimeOutsepenuhnya diabaikan. Ini bukan masalah besar untuk proyek saya, tetapi ini adalah tambahan yang aneh dan tidak diinginkan.
Rvervuurt
Untuk animasi kami yang disebut setTimeout secara berurutan, solusinya bagi kami hanyalah memastikan bahwa kami mengingat gagang / ID timer (dikembalikan dari setTimeout) dan sebelum kami mengatur timer baru, pertama-tama kita memanggil clearTimeout jika kita sudah mendapat pegangan. Dalam kasus kami, ini berarti bahwa ketika Anda kembali ke tab, mungkin ada beberapa keanehan awal dalam hal apa yang dimainkan animasi tetapi memilah dirinya dengan cukup cepat dan animasi biasa dilanjutkan. Kami pikir ini adalah masalah dengan kode keluar pada awalnya.
Aksi Dan

Jawaban:

88

Saya baru-baru ini bertanya tentang ini dan itu adalah perilaku dengan desain. Ketika sebuah tab tidak aktif, fungsi hanya maksimum satu kali per detik. Ini adalah perubahan kodenya .

Mungkin ini akan membantu: Bagaimana saya bisa membuat setInterval juga berfungsi ketika sebuah tab tidak aktif di Chrome?

TL; DR: gunakan Pekerja Web .

pimvdb
sumber
3
terima kasih, saya seharusnya melihat dengan 'tab tidak aktif'. Tidak menjadi penutur asli bahasa Inggris terkadang menjadi kendala.
KooiInc
1
@ Koilnc: Tidak masalah :) Saya juga bukan penutur asli bahasa Inggris.
pimvdb
22

Ada solusi untuk menggunakan Pekerja Web, karena mereka berjalan dalam proses terpisah dan tidak melambat

Saya telah menulis skrip kecil yang dapat digunakan tanpa perubahan pada kode Anda - ia hanya mengabaikan fungsi setTimeout, clearTimeout, setInterval, clearInterval

Cukup sertakan sebelum semua kode Anda

http://github.com/turuslan/HackTimer

Ruslan Tushov
sumber
7
Itu bagus dan sadar bahwa: 1. Pekerja tidak memiliki akses ke DOM, 2. Pekerja hanya akan dieksekusi jika mereka memiliki file sendiri. Ini bukan pengganti drop-in untuk setTimeout untuk banyak kasus.
Madara's Ghost
1
Anda benar, tetapi beberapa peramban modern memungkinkan untuk menggunakan pekerja tanpa file mereka sendiri dengan menggunakan Blobs ( html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers )
Ruslan Tushov
1
Bahkan dengan itu, Pekerja Web kehilangan banyak fungsi (yaitu, DOM) yang memungkinkan mereka menjadi pengganti yang aman untuk setTimeout dan rekan.
Hantu Madara
Bagaimana dengan kode yang harus dijalankan di ujung depan, misalnya, tugas pemrosesan grafis berat yang ingin kami selesaikan sementara kami melakukan hal-hal lain?
Michael
Nah, Anda bisa membuat Pekerja, pekerja layanan dan menggunakan kanvas API menggunakan url data. new Worker('data:text/javascript,(' + function myWorkerCode () { /*...*/ } + '()'). Ini juga cara yang bagus untuk memeriksa apakah Anda memiliki dukungan ekspresi impor:try { eval('import("data:text/javascript,void 0")') } catch (e) { /* no support! */ }
Fábio Santos
9

Memainkan ~ suara kosong memaksa browser untuk mempertahankan kinerja - saya menemukannya setelah membaca komentar ini: Bagaimana cara membuat JavaScript berjalan pada kecepatan normal di Chrome bahkan ketika tab tidak aktif?

Saya membutuhkan kinerja tanpa batas sesuai permintaan untuk permainan browser yang menggunakan WebSockets, jadi saya tahu dari pengalaman bahwa menggunakan WebSockets tidak menjamin kinerja yang tidak terbatas, tetapi dari tes, memainkan file audio tampaknya memastikannya

Inilah 2 loop audio kosong yang saya buat untuk tujuan ini, Anda dapat menggunakannya secara bebas, secara komersial: http://adventure.land/sounds/loops/empty_loop_for_js_performance.ogg http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav

(Termasuk kebisingan -58db, -60db tidak berfungsi)

Saya memainkannya, sesuai permintaan pengguna, dengan 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,
    });
}

Sangat menyedihkan bahwa tidak ada metode bawaan untuk mengaktifkan / menonaktifkan kinerja javascript penuh secara default, namun, penambang crypto dapat membajak semua utas komputasi Anda menggunakan Pekerja Web tanpa ada permintaan: |

Kaan Soral
sumber
Terima kasih, 58db sangat mudah didengar dengan headphone, tetapi mematikan situs memecahkan masalah itu
Kaan Soral
1

Saya telah merilis paket npm interval pekerja yang mengatur implementasi InInvalval dan ClearInterval dengan menggunakan Web-Workers untuk menjaga dan menjalankan tab yang tidak aktif untuk Chrome, Firefox, dan IE.

Sebagian besar peramban modern (Chrome, Firefox, dan IE), interval (penghitung waktu jendela) dijepit untuk mengaktifkan tidak lebih dari sekali per detik dalam tab tidak aktif.

Anda dapat menemukan informasi lebih lanjut tentang

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

gorkemcnr
sumber
0

Saya memperbarui inti jQuery saya ke 1.9.1, dan itu memecahkan perbedaan Interval di tab tidak aktif. Saya akan mencobanya terlebih dahulu, kemudian melihat ke opsi override kode lainnya.

Carey Estes
sumber
dari versi mana Anda meningkatkan? Saya mengalami beberapa masalah timeout (slider galeri) dengan versi ~ 1.6
dmi3y
0

di sini adalah solusi saya yang mendapatkan milidetik saat ini, dan membandingkannya dengan milidetik bahwa fungsi itu dibuat. untuk interval, itu akan memperbarui milidetik ketika menjalankan fungsi. Anda juga dapat mengambil interval / batas waktu dengan id.

<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>
SwiftNinjaPro
sumber