Chrome 88'den itibaren zincirlenmiş JS zamanlayıcıların yoğun şekilde kısıtlanması

Jake Archibald
Jake Archibald

Chrome 88 (Ocak 2021), belirli durumlarda gizli sayfalar için zincirleme JavaScript zamanlayıcılarını büyük ölçüde kısıtlayacaktır. Bu işlem CPU kullanımını azaltarak pil kullanımını da azaltır. Bunun davranışı değiştirdiği bazı uç durumlar vardır ancak zamanlayıcılar genellikle farklı bir API'nin daha verimli ve güvenilir olacağı yerlerde kullanılır.

Bu jargon oldukça ağır ve biraz belirsizdi. Konuya yakından bakalım...

Terminoloji

Gizli sayfalar

Genel olarak gizli, farklı bir sekmenin etkin olduğu veya pencerenin küçültüldüğü anlamına gelir. Ancak tarayıcılar, içeriği tamamen görünmezken bir sayfanın gizlendiğini kabul edebilir. Burada bazı tarayıcılar diğerlerinden daha gelişmiştir ancak tarayıcının görünürlüğün değiştiğini düşündüğünde bunu izlemek için her zaman page visibility API'yi kullanabilirsiniz.

JavaScript zamanlayıcılar

JavaScript zamanlayıcıları ile setTimeout ve setInterval özelliklerini kastediyorum. Bu özellikler, ileride bir geri arama planlamanıza olanak tanır. Zamanlayıcılar faydalıdır ve kullanımdan kalkmaz, ancak bazen bir etkinliğin daha verimli ve daha doğru olacağı durumlarda yoklamak için kullanılırlar.

Zincirleme zamanlayıcılar

setTimeout geri çağırmasıyla aynı görevde setTimeout yöntemini çağırırsanız ikinci çağrı "zincirli" olur. setInterval ile her yineleme, zincirinin bir parçasıdır. Bunu daha kolay anlamak için kod kullanabilirsiniz:

let chainCount = 0;

setInterval(() => {
  chainCount++;
  console.log(`This is number ${chainCount} in the chain`);
}, 500);

Ve:

let chainCount = 0;

function setTimeoutChain() {
  setTimeout(() => {
    chainCount++;
    console.log(`This is number ${chainCount} in the chain`);
    setTimeoutChain();
  }, 500);
}

Kısıtlama nasıl çalışır?

Kısıtlama işlemi aşamalı olarak gerçekleşir:

Minimum sınırlama

Bu durum, aşağıdakilerden herhangi biri geçerli olduğunda programlanmış zamanlayıcılarda görülür:

  • Sayfa görünür olmalıdır.
  • Sayfa son 30 saniye içinde gürültü yapmaya başladı. Bu, ses oluşturma API'lerinin herhangi birinden olabilir ancak sessiz ses parçası sayılmaz.

İstenen zaman aşımı süresi 4 ms'den az olmadığı ve zincir sayısı 5 ya da daha fazla olmadığı sürece (zaman aşımı 4 ms'ye ayarlanacak) zamanlayıcı kısıtlanmaz. Bu yeni bir şey değil. Tarayıcılar bunu yıllardır yapıyor.

Kısıtlama

Bu durum, minimum kısıtlama uygulanmadığında programlanmış zamanlayıcılarda geçerli olur ve aşağıdakilerden herhangi biri doğrudur:

  • zincir sayısı 5'ten azsa.
  • Sayfa 5 dakikadan daha kısa süredir gizlendi.
  • WebRTC kullanılıyor. Özellikle, "açık" RTCDataChannel veya "canlı" MediaStreamTrack içeren bir RTCPeerConnection öğesi vardır.

Tarayıcı, bu gruptaki zamanlayıcıları saniyede bir kez kontrol eder. Bunlar saniyede yalnızca bir kez kontrol edildiğinden, benzer bir zaman aşımına sahip kronometreler birlikte gruplandırılarak sekmenin kodu çalıştırması için gereken süre birleştirilir. Bu da yeni bir şey değil; tarayıcılar bunu yıllardır bir dereceye kadar yapıyor.

Yoğun kısıtlama

Tamam, işte Chrome 88'deki yeni bölüm. Planlanmış zamanlayıcılarda minimum kısıtlama veya kısıtlama koşullarından hiçbiri geçerli olmadığında ve aşağıdaki koşulların tümü geçerli olduğunda yoğun kısıtlama uygulanır:

  • Sayfa 5 dakikadan uzun süredir gizlenmiş.
  • zincir sayısı 5 veya daha fazlaysa.
  • Sayfa en az 30 saniyedir sessiz kalmıştır.
  • WebRTC kullanılmıyor.

Bu durumda tarayıcı, bu gruptaki zamanlayıcıları dakika başına bir kez kontrol eder. Daha önce olduğu gibi bu, zamanlayıcıların dakika dakika kontroller halinde gruplanacağı anlamına gelir.

Geçici çözümler

Genellikle zamanlayıcı yerine daha iyi bir alternatif vardır veya zamanlayıcılar CPU'ya ve pil ömrüne daha duyarlı olması için başka bir şeyle birleştirilebilir.

Eyalet oylaması

Bu, zamanlayıcıların en yaygın (yanlış) kullanımıdır. Zamanlayıcılar bir şeylerin değişip değişmediğini görmek için sürekli olarak kontrol etmek veya anket yapmak için kullanılırlar. Çoğu durumda, değişiklik gerçekleştiğinde bunların size bildirdiği bir push vardır. Böylece sürekli kontrol etmek zorunda kalmazsınız. Aynı sonucu elde eden bir olay olup olmadığına bakın.

Bazı örnekler:

Bildirimi belirli bir zamanda göstermek isterseniz bildirim tetikleyicileri de vardır.

Animasyonlar

Animasyon görsel öğelerdir. Bu nedenle, sayfa gizlendiğinde CPU zamanını kullanmamalıdır.

requestAnimationFrame, animasyon çalışmalarını programlama konusunda JavaScript zamanlayıcılarından çok daha iyidir. Cihazın yenileme hızıyla senkronize edilir ve görüntülenebilir her kare için yalnızca bir geri çağırma olmasını sağlar ve bu kareyi oluşturmak için gereken maksimum süreyi elde edersiniz. Ayrıca requestAnimationFrame, sayfanın görünmesini bekler ve böylece sayfa gizlendiğinde CPU kullanmaz.

Animasyonunuzun tamamını önceden beyan edebiliyorsanız CSS animasyonlarını veya web animasyonları API'sini kullanmayı düşünün. Bunların requestAnimationFrame ile aynı avantajları vardır ancak tarayıcı, otomatik birleştirme gibi ek optimizasyonlar gerçekleştirebilir ve genellikle bunların kullanımı daha kolaydır.

Animasyonunuzun kare hızı düşükse (yanıp sönen imleç gibi) zamanlayıcılar şu anda en iyi seçenektir ancak her ikisinden de en iyi şekilde yararlanmak için zamanlayıcıları requestAnimationFrame ile birleştirebilirsiniz:

function animationInterval(ms, signal, callback) {
  const start = document.timeline.currentTime;

  function frame(time) {
    if (signal.aborted) return;
    callback(time);
    scheduleFrame(time);
  }

  function scheduleFrame(time) {
    const elapsed = time - start;
    const roundedElapsed = Math.round(elapsed / ms) * ms;
    const targetNext = start + roundedElapsed + ms;
    const delay = targetNext - performance.now();
    setTimeout(() => requestAnimationFrame(frame), delay);
  }

  scheduleFrame(start);
}

Kullanım:

const controller = new AbortController();

// Create an animation callback every second:
animationInterval(1000, controller.signal, time => {
  console.log('tick!', time);
});

// And stop it:
controller.abort();

Test

Bu değişiklik, Chrome 88 sürümündeki (Ocak 2021) tüm Chrome kullanıcıları için etkinleştirilecektir. Bu özellik şu anda Chrome Beta, Yeni geliştirilenler ve Canary kullanıcılarının% 50'si için etkindir. Test etmek istiyorsanız Chrome Beta, Dev veya Canary'yi başlatırken şu komut satırı işaretini kullanın:

--enable-features="IntensiveWakeUpThrottling:grace_period_seconds/10,OptOutZeroTimeoutTimersFromThrottling,AllowAggressiveThrottlingWithWebSocket"

grace_period_seconds/10 bağımsız değişkeni, 5 dakikanın tamamı yerine gizlendikten 10 saniye sonra sayfa gizlendikten sonra yoğun kısıtlamaya neden olur. Böylece kısıtlamanın etkisini görebilirsiniz.

Gelecek

Zamanlayıcılar aşırı CPU kullanımının bir kaynağı olduğundan, web içeriğini bozmadan onları kısıtlama yollarına ve kullanım alanlarına uygun hale getirmek için ekleyip değiştirebileceğimiz API'lere bakmaya devam edeceğiz. Kişisel olarak, düşük frekanslı etkili animasyon geri çağırmaları yerine animationInterval ihtiyacını ortadan kaldırmak istiyorum. Sorularınız varsa lütfen Twitter'dan bize ulaşın!

Unsplash'ta Heather Zabriskie tarafından yüklenen başlık fotoğrafı.