Kullanıcı girişine hızlı yanıt veren web siteleri oluşturmak, web performansının en zorlu yönlerinden biri olmuştur. Chrome Ekibi, web geliştiricilerin bu zorluğu aşmasına yardımcı olmak için yoğun bir şekilde çalışmaktadır. Yalnızca bu yıl, Interaction to Next Paint (INP) metriğinin deneysel durumdan beklemede durumuna geçeceği duyuruldu. INP, Mart 2024'te Core Web Vital olarak İlk Giriş Gecikmesi'nin (FID) yerini almaya hazırlanıyor.
Web geliştiricilerin web sitelerini olabildiğince hızlı hale getirmelerine yardımcı olacak yeni API'ler sunma çabası kapsamında Chrome Ekibi, şu anda Chrome'un 115. sürümünden itibaren scheduler.yield için bir kaynak denemesi yürütmektedir. scheduler.yield, planlayıcı API'sine eklenmesi önerilen yeni bir özelliktir. Bu özellik, geleneksel olarak kullanılan yöntemlere kıyasla kontrolü ana işleme geri vermenin daha kolay ve daha iyi bir yolunu sunar.
Gelir elde etme
JavaScript, görevleri tamamlamak için run-to-completion modelini kullanır. Bu, bir görev ana iş parçacığında çalışırken tamamlanması için gereken süre boyunca çalıştığı anlamına gelir. Bir görev tamamlandığında kontrol ana iş parçacığına bırakılır. Bu sayede ana iş parçacığı, sıradaki bir sonraki görevi işleyebilir.
Bir görevin asla tamamlanmadığı (ör. sonsuz döngü) gibi uç durumlar dışında, kontrolü bırakma, JavaScript'in görev planlama mantığının kaçınılmaz bir yönüdür. Bu olacak. Sadece ne zaman olacağı önemli ve ne kadar erken olursa o kadar iyi. Görevlerin çalışması çok uzun sürdüğünde (tam olarak 50 milisaniyeden uzun) bu görevler uzun görevler olarak kabul edilir.
Uzun görevler, tarayıcının kullanıcı girişine yanıt verme yeteneğini geciktirdiği için sayfanın tepkisinin yavaş olmasına neden olur. Uzun görevler ne kadar sık gerçekleşirse ve ne kadar uzun sürerse kullanıcıların sayfanın yavaş olduğu, hatta tamamen bozulduğu izlenimini edinme olasılığı o kadar artar.
Ancak kodunuz tarayıcıda bir görevi başlatıyor olsa bile kontrolün ana iş parçacığına geri verilmesi için bu görevin tamamlanmasını beklemeniz gerekmez. Bir görevde açıkça izin vererek sayfadaki kullanıcı girişine verilen yanıtı iyileştirebilirsiniz. Bu işlem, görevi bir sonraki uygun fırsatta tamamlanacak şekilde böler. Bu sayede diğer görevler, uzun görevlerin tamamlanmasını beklemek zorunda kalmadan ana iş parçacığında daha kısa sürede çalışabilir.
Açıkça izin verdiğinizde tarayıcıya "Hey, yapacağım işin biraz zaman alabileceğini anlıyorum ve kullanıcı girişine veya önemli olabilecek diğer görevlere yanıt vermeden önce bu işin tamamını yapmanı istemiyorum" diyorsunuz. Bu araç, geliştiricilerin araç kutusunda yer alan ve kullanıcı deneyimini iyileştirmek için kullanılabilecek değerli bir araçtır.
Mevcut gelir artırma stratejileriyle ilgili sorun
Genel bir kontrolü bırakma yöntemi, setTimeout yöntemini 0 zaman aşımı değeriyle kullanır. Bu, setTimeout'ya iletilen geri çağırma, kalan işi ayrı bir göreve taşıyarak sonraki yürütme için sıraya alınmasını sağladığından çalışır. Tarayıcının kendi kendine işlem yapmasını beklemek yerine "Bu büyük iş parçasını daha küçük parçalara ayır" diyorsunuz.
Ancak setTimeout ile kontrol bırakmak, istenmeyen bir yan etkiye neden olabilir: Kontrol bırakma noktasından sonra gelen işler, görev sırasının en sonuna gider. Kullanıcı etkileşimleriyle planlanan görevler, olması gerektiği gibi sıranın en önüne alınmaya devam eder. Ancak açıkça izin verdikten sonra yapmak istediğiniz kalan işler, sıraya kendisinden önce alınan rakip kaynaklardaki diğer görevler nedeniyle daha da gecikebilir.
Bu özelliği uygulamada görmek için bu Codepen demosunu deneyin veya aşağıdaki yerleştirilmiş sürümde bu özellik üzerinde denemeler yapın. Demoda, tıklayabileceğiniz birkaç düğme ve bunların altında, görevlerin ne zaman çalıştırıldığını kaydeden bir kutu bulunur. Sayfaya geldiğinizde aşağıdaki işlemleri yapın:
- Görevleri düzenli olarak çalıştır etiketli üstteki düğmeyi tıklayın. Bu düğme, engelleyici görevlerin belirli aralıklarla çalıştırılmasını planlar. Bu düğmeyi tıkladığınızda görev günlüğüne Ran blocking task with
setInterval(setIntervalile engelleme görevi çalıştırıldı) yazan birkaç mesaj eklenir. - Ardından, Her yinelemede
setTimeoutile sonuç veren döngüyü çalıştır etiketli düğmeyi tıklayın.
Demonun alt kısmındaki kutuda şuna benzer bir ifade görürsünüz:
Processing loop item 1
Processing loop item 2
Ran blocking task via setInterval
Processing loop item 3
Ran blocking task via setInterval
Processing loop item 4
Ran blocking task via setInterval
Processing loop item 5
Ran blocking task via setInterval
Ran blocking task via setInterval
Bu çıktı, setTimeout ile verim elde edildiğinde ortaya çıkan "görev sırasının sonu" davranışını gösterir. Beş öğeyi işleyen ve her biri işlendikten sonra setTimeout ile sonuçlanan döngü.
Bu, web'deki yaygın bir sorunu gösterir: Özellikle üçüncü taraf komut dosyaları olmak üzere komut dosyalarının, belirli aralıklarla çalışan bir zamanlayıcı işlevi kaydetmesi alışılmadık bir durum değildir. setTimeout ile verim elde etmenin getirdiği "görev kuyruğunun sonu" davranışı, diğer görev kaynaklarından gelen işlerin, döngünün verim elde ettikten sonra yapması gereken kalan işlerden önce sıraya alınabileceği anlamına gelir.
Uygulamanıza bağlı olarak bu durum istenen bir sonuç olabilir veya olmayabilir. Ancak çoğu durumda, geliştiricilerin ana iş parçacığının kontrolünü bu kadar kolay bırakmak istememesinin nedeni bu davranıştır. Kontrolü bırakmak, kullanıcı etkileşimlerinin daha erken çalışmasına olanak tanıdığı için iyidir ancak kullanıcı etkileşimi olmayan diğer işlerin de ana iş parçacığında zaman kazanmasına olanak tanır. Bu gerçek bir sorun olsa da scheduler.yield bu sorunu çözmenize yardımcı olabilir.
scheduler.yield moduna geç
scheduler.yield, Chrome'un 115 sürümünden beri bir flag'in arkasında deneysel web platformu özelliği olarak kullanılabilir. Aklınıza gelebilecek sorulardan biri "setTimeout zaten bunu yapıyorken neden yield için özel bir fonksiyona ihtiyacım var?" olabilir.
setTimeout'ın tasarım hedefinin kontrolü bırakmak olmadığı, bunun yerine 0 zaman aşımı değeri belirtilmiş olsa bile geri çağırma işleminin gelecekte daha sonra çalıştırılacak şekilde planlanmasının hoş bir yan etkisi olduğu belirtilmelidir. Ancak, setTimeout ile verim elde etmenin, kalan işi görev sırasının arkasına göndereceğini unutmamak önemlidir. Varsayılan olarak scheduler.yield, kalan işleri sıranın önüne gönderir. Bu, kontrolü bıraktıktan hemen sonra devam ettirmek istediğiniz çalışmaların diğer kaynaklardaki görevlere (kullanıcı etkileşimleri hariç) göre öncelikli olacağı anlamına gelir.
scheduler.yield, ana iş parçacığına geçiş yapan ve çağrıldığında Promise döndüren bir işlevdir. Bu, await işlevinde async kullanabileceğiniz anlamına gelir:
async function yieldy () {
// Do some work...
// ...
// Yield!
await scheduler.yield();
// Do some more work...
// ...
}
scheduler.yield simgesini kullanmak için aşağıdakileri yapın:
chrome://flagsadresine gidiş rotasını izle.- Deneysel web platformu özellikleri denemesini etkinleştirin. Bu işlemi yaptıktan sonra Chrome'u yeniden başlatmanız gerekebilir.
- Demo sayfasına gidin veya bu listenin ardından aşağıdaki yerleştirilmiş sürümünü kullanın.
- Görevleri düzenli olarak çalıştır etiketli üstteki düğmeyi tıklayın.
- Son olarak, Her yinelemede
scheduler.yieldile sonuç veren döngüyü çalıştır etiketli düğmeyi tıklayın.
Sayfanın alt kısmındaki kutuda şu şekilde bir çıktı gösterilir:
Processing loop item 1
Processing loop item 2
Processing loop item 3
Processing loop item 4
Processing loop item 5
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval
setTimeout kullanılarak yapılan demodan farklı olarak, döngünün her yinelemeden sonra kontrolü bırakmasına rağmen kalan işi kuyruğun arkasına değil, önüne gönderdiğini görebilirsiniz. Bu sayede iki dünyanın en iyi özelliklerinden yararlanabilirsiniz: Web sitenizdeki giriş yanıt hızını artırmak için kontrolü bırakabilir, ancak kontrolü bıraktıktan sonra tamamlamak istediğiniz işin gecikmemesini de sağlayabilirsiniz.
Mutlaka deneyin!
scheduler.yield özelliğini ilginç buluyorsanız ve denemek istiyorsanız Chrome'un 115 sürümünden itibaren iki şekilde deneyebilirsiniz:
scheduler.yieldile yerel olarak deneme yapmak istiyorsanız Chrome'un adres çubuğunascheduler.yieldyazıp Enter tuşuna basın ve Experimental Web Platform Features (Deneysel Web Platformu Özellikleri) bölümündeki açılır listeden Enable'ı (Etkinleştir) seçin.chrome://flagsBu işlem,scheduler.yield(ve diğer deneysel özellikler) yalnızca Chrome'un sizin örneğinizde kullanılabilir hale getirir.- Herkese açık bir kaynakta gerçek Chromium kullanıcıları için
scheduler.yield'yı etkinleştirmek istiyorsanızscheduler.yieldkaynak denemesine kaydolmanız gerekir. Bu sayede, belirli bir süre boyunca önerilen özellikleri güvenli bir şekilde deneyebilir ve Chrome Ekibi'ne bu özelliklerin sahada nasıl kullanıldığı hakkında değerli bilgiler verebilirsiniz. Kaynak denemelerinin işleyiş şekli hakkında daha fazla bilgi için bu kılavuzu inceleyin.
scheduler.yield özelliğini, bu özelliği uygulamayan tarayıcıları desteklemeye devam ederken nasıl kullanacağınız hedeflerinize bağlıdır. Resmi polyfill'i kullanabilirsiniz. Aşağıdaki durumlar geçerliyse polyfill kullanışlıdır:
- Görevleri planlamak için uygulamanızda
scheduler.postTaskkullanıyorsunuz. - Görev ve gelir önceliklerini belirleyebilmek istiyorsanız.
scheduler.postTaskAPI'nin sunduğuTaskControllersınıfını kullanarak görevleri iptal etmek veya yeniden önceliklendirmek istiyorsunuz.
Bu durum sizin için geçerli değilse polyfill sizin için uygun olmayabilir. Bu durumda, kendi yedek çözümünüzü birkaç şekilde kullanabilirsiniz. İlk yaklaşımda, varsa scheduler.yield kullanılır, yoksa setTimeout'ye geri dönülür:
// A function for shimming scheduler.yield and setTimeout:
function yieldToMain () {
// Use scheduler.yield if it exists:
if ('scheduler' in window && 'yield' in scheduler) {
return scheduler.yield();
}
// Fall back to setTimeout:
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
// Example usage:
async function doWork () {
// Do some work:
// ...
await yieldToMain();
// Do some other work:
// ...
}
Bu yöntem işe yarayabilir ancak tahmin edebileceğiniz gibi scheduler.yield'yı desteklemeyen tarayıcılar, "sıranın önünde" davranışı olmadan sonuç verir. Bu, hiç getiri elde etmemeyi tercih edeceğiniz anlamına geliyorsa scheduler.yield varsa kullanan ancak yoksa hiç getiri elde etmeyen başka bir yaklaşım deneyebilirsiniz:
// A function for shimming scheduler.yield with no fallback:
function yieldToMain () {
// Use scheduler.yield if it exists:
if ('scheduler' in window && 'yield' in scheduler) {
return scheduler.yield();
}
// Fall back to nothing:
return;
}
// Example usage:
async function doWork () {
// Do some work:
// ...
await yieldToMain();
// Do some other work:
// ...
}
scheduler.yield, planlayıcı API'sine heyecan verici bir ektir. Geliştiricilerin, mevcut getiri stratejilerine kıyasla yanıt verme hızını artırmasını kolaylaştıracağı umulmaktadır. scheduler.yield sizin için faydalı bir API gibi görünüyorsa lütfen iyileştirilmesine yardımcı olmak için araştırmamıza katılın ve daha da geliştirilebileceği yönünde geri bildirimde bulunun.
Unsplash'ten Jonathan Allison tarafından çekilen hero resim.