Chrome 88 (Ocak 2021), belirli koşullarda gizli sayfalar için zincirlenmiş JavaScript zamanlayıcılarını büyük ölçüde azaltacaktır. Bu işlem, CPU kullanımını azaltır ve dolayısıyla pil kullanımını da azaltır. Bunun davranışı değiştireceği bazı uç durumlar vardır ancak zamanlayıcılar genellikle farklı bir API'nin daha verimli ve daha güvenilir olacağı durumlarda kullanılır.
Tamam, bu oldukça jargon ağırlıklı ve biraz belirsizdi. Birlikte bakalım…
Terminoloji
Gizli sayfalar
Genellikle 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ünmeyen sayfaları da gizli olarak kabul edebilir. Bazı tarayıcılar bu konuda diğerlerinden daha ileri gider ancak tarayıcının görünürlüğün değiştiğini düşündüğü durumları izlemek için her zaman sayfa görünürlüğü API'sini kullanabilirsiniz.
JavaScript zamanlayıcıları
JavaScript zamanlayıcıları derken, gelecekte bir geri çağırma planlamanıza olanak tanıyan setTimeout
ve setInterval
'den bahsediyorum. Zamanlayıcılar kullanışlıdır ve kullanımdan kaldırılmayacaktır. Ancak bazen bir etkinliğin daha verimli ve daha doğru olacağı durumlarda durumu anlamak için kullanılırlar.
Zincirlenmiş zamanlayıcılar
setTimeout
çağrısını aynı görevde setTimeout
geri çağırma olarak yaparsanız ikinci çağrı "zincirlenir". setInterval
ile her iterasyon zincirinin bir parçasıdır. Bu, kodla daha kolay anlaşılabilir:
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);
}
Yavaşlatma nasıl çalışır?
Yavaşlatma aşamalı olarak gerçekleşir:
Minimum kısıtlama
Bu durum, aşağıdakilerden herhangisi doğru olduğunda planlanan zamanlayıcılarda gerçekleşir:
- Sayfa görünür olmalıdır.
- Sayfa son 30 saniye içinde ses çıkarmıştır. Bu, ses üreten API'lerden herhangi biri olabilir ancak sessiz ses parçası sayılmaz.
İstenilen zaman aşımı 4 ms'den az ve zincir sayısı 5 veya daha fazla değilse zamanlayıcı kısıtlanmaz. Bu durumda zaman aşımı 4 ms olarak ayarlanır. Bu durum yeni değil; tarayıcılar bunu yıllardır yapıyor.
Kısıtlama
Bu durum, minimum tarama geçerli olmadığında ve aşağıdakilerden herhangisi geçerli olduğunda planlanan zamanlayıcılarda görülür:
- Zincir sayısı 5'ten az.
- Sayfa 5 dakikadan kısa bir süredir gizli.
- WebRTC kullanılıyor. Daha açık belirtmek gerekirse, "açık"
RTCDataChannel
veya "canlı"MediaStreamTrack
içeren birRTCPeerConnection
vardır.
Tarayıcı, bu gruptaki zamanlayıcıları saniyede bir kez kontrol eder. Yalnızca saniyede bir kontrol edildiğinden, benzer zaman aşımına sahip zamanlayıcılar gruplandırılır ve sekmenin kod çalıştırması için gereken süre birleştirilir. Bu da yeni bir durum değil. Tarayıcılar yıllardır bir dereceye kadar bunu yapıyor.
Yoğun kısıtlama
Tamam, Chrome 88'deki yeniliklerden bahsedeceğim. Yoğun tarama, minimum tarama veya tarama koşullarından hiçbiri geçerli olmadığında ve aşağıdaki koşulların tümü doğru olduğunda planlanan zamanlayıcılarda gerçekleşir:
- Sayfa 5 dakikadan uzun süredir gizli.
- Zincir sayısı 5 veya daha fazladır.
- Sayfa en az 30 saniye boyunca sessizse
- WebRTC kullanılmıyor.
Bu durumda tarayıcı, bu gruptaki zamanlayıcıları dakikada bir kez kontrol eder. Daha önce olduğu gibi, bu da zamanlayıcıların bu dakikalık kontrollerde birlikte gruplandırılacağı anlamına gelir.
Geçici çözümler
Zamanlayıcılar genellikle daha iyi bir alternatife sahiptir veya CPU'lara ve pil ömrüne daha az zarar vermesi için başka bir şeyle birlikte kullanılabilir.
Eyalet anketleri
Zamanlayıcıların en yaygın (yanlış) kullanımı, bir şeyin değişip değişmediğini görmek için sürekli olarak kontrol etmek veya anket yapmak için kullanılmasıdır. Çoğu durumda, bir push eşdeğeri vardır. Bu eşdeğer, değişiklik olduğunda size bildirir. Böylece, sürekli kontrol etmeniz gerekmez. Aynı sonucu sağlayan bir etkinlik olup olmadığına bakın.
Bazı örnekler:
- Bir öğenin görüntü alanına ne zaman girdiğini bilmeniz gerekiyorsa
IntersectionObserver
öğesini kullanın. - Bir öğenin boyutunun ne zaman değiştiğini bilmeniz gerekiyorsa
ResizeObserver
öğesini kullanın. - DOM'un ne zaman değiştiğini bilmeniz gerekiyorsa
MutationObserver
veya özel öğe yaşam döngüsü geri çağırma işlevlerini kullanın. - Bir sunucuyu anketlemek yerine web soketlerini, sunucu tarafından gönderilen etkinlikleri, push mesajlarını veya aktarılan akışları kullanabilirsiniz.
- Ses/videodaki sahne değişikliklerine tepki vermeniz gerekiyorsa
timeupdate
veended
gibi etkinlikleri kullanın. Her kareyle ilgili bir işlem yapmanız gerekiyorsarequestVideoFrameCallback
değerini kullanın.
Belirli bir zamanda bildirim göstermek isterseniz bildirim tetikleyicileri de kullanabilirsiniz.
Animasyon
Animasyon görsel bir öğe olduğundan sayfa gizliyken CPU zamanı kullanmamalıdır.
requestAnimationFrame
, animasyon çalışmalarını planlama konusunda JavaScript zamanlayıcılarından çok daha iyidir. Cihazın yenileme hızıyla senkronize olur. Böylece, görüntülenebilir kare başına yalnızca bir geri çağırma alırsınız ve bu kareyi oluşturmak için maksimum süreyi elde edersiniz. Ayrıca requestAnimationFrame
, sayfanın görünür olmasını bekler. Bu nedenle, sayfa gizliyken CPU kullanmaz.
Animasyonunuzun tamamını önceden belirtebiliyorsanız CSS animasyonlarını veya web animasyon API'sini kullanabilirsiniz. Bunlar requestAnimationFrame
ile aynı avantajlara sahiptir ancak tarayıcı, otomatik kompozisyon gibi ek optimizasyonlar gerçekleştirebilir ve genellikle daha kolay kullanılır.
Animasyonunuzun kare hızı düşükse (ör. yanıp sönen bir imlec) zamanlayıcılar şu anda en iyi seçenektir. Ancak iki dünyanın da en iyisini elde etmek için bunları 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'de (Ocak 2021) tüm Chrome kullanıcıları için etkinleştirilecek. Bu özellik şu anda Chrome Beta, Geliştirici ve Canary kullanıcılarının% 50'sinde etkindir. Bu özelliği test etmek istiyorsanız Chrome Beta, Dev veya Canary'ı 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, yoğun kısıtlamanın 5 dakikanın tamamı yerine sayfa gizlendikten 10 saniye sonra etkinleşmesine neden olur. Bu sayede kısıtlamanın etkisini daha kolay görebilirsiniz.
Gelecek
Zamanlayıcılar aşırı CPU kullanımının kaynağı olduğundan, web içeriğini bozmadan bunları nasıl sınırlayabileceğimiz ve kullanım alanlarını karşılamak için hangi API'leri ekleyebileceğimiz/değiştirebileceğimiz üzerinde çalışmaya devam edeceğiz. Kişisel olarak, animationInterval
ihtiyacını ortadan kaldırıp verimli, düşük frekanslı animasyon geri çağırmalarını tercih ederim. Sorunuz olursa lütfen Twitter üzerinden bana ulaşın.
Unsplash'taki Heather Zabriskie tarafından çekilen üstbilgi fotoğrafı.