Sekme veya pencere etkin olmadığında tarayıcılar Javascript'i nasıl duraklatır / değiştirir?


168

Arka plan: İnsanların dikkat edip etmediğini tespit etmesi gereken bazı kullanıcı arayüzü testleri yapıyorum. Ancak, bu soru sayfa görünürlüğü API'sı ile ilgili değildir .

Özellikle, geçerli sekme etkin değilse veya tarayıcı penceresi etkin değilse, farklı tarayıcılarda Javascript kodumun nasıl etkileneceğini bilmek istiyorum. Şimdiye kadar aşağıdakileri kazdım:

Aşağıdaki sorularım var:

  • Mobil tarayıcılar dışında, masaüstü tarayıcıları bir sekme etkin değilken JS yürütmeyi duraklatır mı? Ne zaman ve hangi tarayıcılar?
  • Hangi tarayıcılar setIntervaltekrarı azaltır ? Sadece bir sınıra mı, yoksa yüzde mi düşürüldü? Örneğin, 5000 ms'lik bir tekrara karşı 10 ms'lik bir tekrarım varsa, her biri nasıl etkilenir?
  • Bu değişiklikler , yalnızca sekme yerine pencere odak dışındaysa gerçekleşir mi? (OS API'sı gerektirdiğinden tespit etmenin daha zor olacağını düşünüyorum.)
  • Etkin bir sekmede gözlenmeyecek başka efektler var mı? Aksi takdirde doğru bir şekilde yürütülecek şeyleri berbat edebilirler mi (yani yukarıda belirtilen Yasemin testleri)?

Duraklatılmışlarsa, Facebook gibi siteler arka plan sekmelerinde sohbet mesajı almaz.
Joseph

1
Evet duraklama yok, ancak sekme / pencere bulanık olduğunda 1000 ms'nin altındaki setInterval/ setTimeoutsürelerinin 1000 ms olarak değiştirildiğini hatırlıyorum
Ian

19
@ProfPickle Webmasterları? Gerçekten mi? Bu bir JS programlama sorusudur.
Andrew Mao

1
Sekme / pencere bulanıklaştığında 1000 ms'nin altındaki @ lan setInterval/ setTimeoutkez 1000 ms olarak değiştirilir. Neyi iletmeye çalıştığınız belli değil
Amol M Kulkarni

4
+1 Harika bir soru. Sekmeler etkin olmadığında sıkıştırma davranışının herhangi bir standardın parçası olmadığına inandığım için tarayıcı davranışlarının yan yana karşılaştırmasını görmek iyi olurdu.
UpTheCreek

Yanıtlar:


190

Birinci Test

Bu amaç için özel olarak bir test yazdım:
Kare Hızı Dağılımı: setInterval vs requestAnimationFrame

Not: Bu test oldukça CPU yoğundur. requestAnimationFrameIE 9- ve Opera 12- tarafından desteklenmez.

Test, bir setIntervalve requestAnimationFramefarklı tarayıcılarda çalışmak için gereken süreyi günlüğe kaydeder ve sonuçları bir dağıtım şeklinde verir. setIntervalFarklı ayarlar altında nasıl çalıştığını görmek için milisaniye sayısını değiştirebilirsiniz . gecikmeler açısından a'ya setTimeoutbenzer şekilde çalışır setInterval. requestAnimationFramegenellikle tarayıcıya bağlı olarak varsayılan olarak 60 fps'dir. Farklı bir sekmeye geçtiğinizde veya etkin olmayan bir pencereniz olduğunda ne olacağını görmek için sayfayı açmanız, farklı bir sekmeye geçmeniz ve bir süre beklemeniz yeterlidir. Etkin olmayan bir sekmede bu işlevler için geçen süreyi günlüğe kaydetmeye devam eder.

Test İki

Bunu test etmenin başka bir yolu da zaman damgasını tekrar tekrar setIntervalve requestAnimationFrameayrı bir konsolda görüntülemek. Sekmeyi veya pencereyi devre dışı bıraktığınızda ne sıklıkta güncellendiğini (veya hiç güncellenip güncellenmediğini) görebilirsiniz.

Sonuçlar

Chrome
Chrome setInterval, sekme etkin olmadığında minimum aralığı yaklaşık 1000 ms ile sınırlar . Aralık 1000 ms'den yüksekse, belirtilen aralıkta çalışır. Pencerenin odak dışında olması önemli değildir, aralık yalnızca farklı bir sekmeye geçtiğinizde sınırlanır. requestAnimationFramesekme etkin olmadığında duraklatılır.

// 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'a ​​benzer şekilde, Firefox setIntervalsekme (pencere değil) etkin olmadığında minimum aralığı yaklaşık 1000 ms ile sınırlar . Ancak, requestAnimationFramesekme etkin olmadığında katlanarak daha yavaş çalışır ve her kare 1s, 2s, 4s, 8s vb.

// 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, sekme etkin olmadığında gecikmeyi sınırlamaz , ancak requestAnimationFrameetkin olmayan sekmelerde duraklar . Pencerenin odak dışında olup olmadığı önemli değildir.

Kenar
Kenar 14'ten başlayarak, setIntervaletkin olmayan sekmelerde 1000 ms ile sınırlanır. requestAnimationFrameetkin olmayan sekmelerde her zaman duraklatılır.

Safari
Tıpkı Chrome gibi, Safari setIntervalde sekme etkin olmadığında 1000 ms'de kapanır. requestAnimationFrameduraklatılır.

Opera
Webkit motorunun kabul edilmesinden bu yana Opera, Chrome ile aynı davranışı sergiliyor. setInterval1000ms ile sınırlıdır ve requestAnimationFramesekme etkin olmadığında duraklatılır.

özet

Etkin olmayan sekmeler için tekrarlama aralıkları:

           setInterval      requestAnimationFrame 
Chrome
9- etkilenmez desteklenmez
10 etkilenmedi duraklatıldı
11+> = 1000 ms duraklatıldı

Firefox
3- etkilenmez desteklenmez
4 etkilenmeyen 1s
5+> = 1000 ms 2 n s (n = işlem yapılmadığından beri geçen kare sayısı)

IE
9- etkilenmez desteklenmez
10+ etkilenmedi duraklatıldı

kenar
13- etkilenmez duraklatıldı
14+> = 1000 ms duraklatıldı

Safari
5- etkilenmez desteklenmez
6 etkilenmedi duraklatıldı
7+> = 1000 ms duraklatıldı

Opera
12- etkilenmez desteklenmez
15+> = 1000 ms duraklatıldı

Mükemmel cevap. setIntervalVe requestAnimationFrame? Dışındaki işlevler için bilinen diğer olası farklar
Andrew Mao

1
@AndrewMao Farkında olduğumdan değil. Ben JS ile tekrar etkinleştirdiysek güvenilir algılamak için bir kütüphane üzerinde çalışırken ben bu konuda rastladım setIntervalve requestAnimationFrame. Bildiğim şey , her ikisinin de Firefox ve Chrome'da aynı minimum arka plan aralığına sahip olması ve diğer tarayıcılarda görünür bir sınır olmaması nedeniyle setTimeoutbenzer şekilde davranmasıdır setInterval.
Antony

2
Firefox setInterval minimum değeri about:config, tarayıcıda URL'yi açıp dom.min_background_timeout_valuedeğeri 1000'den başka bir değere değiştirerek görünüşte değiştirilebilir.
Jonas Berlin

tarayıcı minimize edildiğinde i yeniden sayfasına her 5 saniyede bu kullanabilirim?, burada benim sorudur.
shaijut

1
requestAnimationFrameKullanıcı yalnızca uygulamayı değiştirirse (Alt + Sekme Chrome'un dışındadır) Chrome'un çağrılma hızını duraklatmaz / azaltmaz . Sekme Chrome'da etkin olduğu sürece "kare hızı" aşağı yukarı sabittir.
Marc

11

Ben gözlenen Ne: inaktif tırnaklarına Chrome , bütün sizin setTimeoutiçin (aynı olmalıdır setInterval) daha az bekleme 1000ms yuvarlanır 1000ms . Bence daha uzun zaman aşımları değiştirilmedi.

Chrome 11 ve Firefox 5.0'dan bu yana davranış gibi görünüyor : https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout#Inactive_tabs

Ayrıca, tüm pencere etkin olmadığında bu şekilde davrandığını sanmıyorum (ancak araştırılması oldukça kolay görünüyor).


1
jQuery focusve blurolayları hem sekme hem de pencere anahtarlarını algılar gibi görünür, böylece her iki şekilde de çalışabilir. Ama pencerenin gerçekten görünür olup olmadığını nasıl algıladığını merak ediyorum.
Andrew Mao

2
Aslında jQuery veya Javascript ile dahili tarayıcı uygulaması olduğu için hiçbir bağlantısı yoktur .

Bunu 2016 sonlarında doğrulayabilir misiniz?
vsync

0

Bunları tamamlamak için daha yeni bir yanıt: krom 78.0.3904.108'de farklı bir sekmeye geçtiğimde ve daha sonra geri döndüğümde tüm bu zaman aşımlarının (sadece 1000 ms'nin altındakiler değil) beklenenden biraz daha uzun sürdüğünü fark ettim. Gördüğüm davranış, "Etkin olmayan sekmelerdeki tüm zaman aşımları, maksimum 1000 ms'ye kadar bir miktar daha geciktirilebilir" şeklinde daha doğru bir şekilde açıklanmaktadır . :

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>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.