1. Giriş
Sonraki Boyamayla Etkileşim (INP) hakkında bilgi edinmek için etkileşimli bir demo ve codelab.
Ön koşullar
- HTML ve JavaScript geliştirme hakkında bilgi sahibi olmak.
- Önerilen: INP dokümanlarını okuyun.
Öğrenecekleriniz
- Kullanıcı etkileşimlerinin karşılıklı etkileşimi ve bu etkileşimleri ele alma biçiminizin sayfa yanıt verme üzerindeki etkisi.
- Sorunsuz bir kullanıcı deneyimi için gecikmeler nasıl azaltılır ve ortadan kaldırılır?
İhtiyacınız olanlar
- GitHub'dan kod klonlayabilen ve npm komutlarını çalıştırabilen bir bilgisayar.
- Metin düzenleyici.
- Tüm etkileşim ölçümlerinin çalışabilmesi için Chrome'un güncel bir sürümü.
2. Hazırlanın
Kodu alma ve çalıştırma
Kod, web-vitals-codelabs
deposunda bulunur.
- Terminalinizdeki depoyu klonlayın:
git clone https://github.com/GoogleChromeLabs/web-vitals-codelabs.git
- Klonlanan dizine geçiş:
cd web-vitals-codelabs/understanding-inp
- Bağımlılıkları yükleyin:
npm ci
- Web sunucusunu başlatın:
npm run start
- Tarayıcınızda http://localhost:5173/understanding-inp/ adresini ziyaret edin.
Uygulamaya genel bakış
Sayfanın üst kısmında bir Puan sayacı ve Artır düğmesi bulunur. Tepki verme ve duyarlılık konusunda klasik bir demo
Düğmenin altında dört ölçüm bulunur:
- INP: Genellikle en kötü etkileşim olan geçerli INP puanı.
- Etkileşim: En son etkileşimin puanı.
- FPS: sayfanın saniyedeki ana iş parçacığının kare sayısı.
- Zamanlayıcı: olumsuzlukları görselleştirmeye yardımcı olan çalışan bir zamanlayıcı animasyonu.
Etkileşimleri ölçmek için FPS ve Zamanlayıcı girişleri gerekli değildir. Bunlar, duyarlılığı görselleştirmeyi biraz kolaylaştırmak amacıyla eklenmiştir.
Deneyin
Artır düğmesiyle etkileşimde bulunmaya çalışın ve puan artışını izleyin. INP ve Etkileşim değerleri her artımla değişiyor mu?
INP, kullanıcının etkileşimde bulunduğu andan sayfanın oluşturulan güncellemeyi kullanıcıya gerçekten göstermesine kadar geçen süreyi ölçer.
3. Chrome Geliştirici Araçları ile etkileşimleri ölçme
Diğer Araçlar > bölümünden Geliştirici Araçları'nı açın Geliştirici Araçları menüsünü, sayfayı sağ tıklayıp İncele'yi seçerek veya klavye kısayolunu kullanarak yapabilirsiniz.
Etkileşimleri ölçmek için kullanacağınız Performans paneline geçin.
Ardından, Performans panelinde bir etkileşim yakalayın.
- Kaydet'e basın.
- Sayfayla etkileşimde bulunun (Artır düğmesine basın).
- Kaydı durdurun.
Ortaya çıkan zaman çizelgesinde bir Etkileşimler kanalı görürsünüz. Sol taraftaki üçgeni tıklayarak bu segmenti genişletin.
İki etkileşim görünür. İkincisinde ise W tuşunu kaydırarak veya basılı tutarak yakınlaştırın.
Etkileşimin üzerine geldiğinizde, etkileşimin hızlı olduğunu, işleme süresinde hiç zaman harcamadığını ve giriş gecikmesi ile sunum gecikmesi'nde minimum süreyi görebilirsiniz. Bu sürenin tam uzunluğu makinenizin hızına bağlıdır.
4. Köklü etkinlik işleyiciler
index.js
dosyasını açın ve etkinlik işleyicideki blockFor
işlevinin açıklamasını kaldırın.
Kodun tamamını görün: click_block.html
button.addEventListener('click', () => {
blockFor(1000);
score.incrementAndUpdateUI();
});
Dosyayı kaydedin. Sunucu değişikliği görür ve sayfayı sizin için yeniler.
Sayfayla tekrar etkileşimde bulunmayı deneyin. Etkileşimler önemli ölçüde yavaşlar.
Performans izleme
Performans panelinde başka bir kayıt alarak bunun orada nasıl göründüğünü inceleyin.
Eskiden kısa bir etkileşim şimdi tam bir saniye sürüyor.
Etkileşimin üzerine geldiğinizde, zamanın neredeyse tamamen "İşleme süresi"nde harcandığına dikkat edin. Bu, etkinlik işleyici geri çağırmalarının yürütülmesi için harcanan süredir. Engelleyen blockFor
çağrısı tamamen etkinlik işleyici içinde olduğundan zaman bu şekildedir.
5. Deneme: işleme süresi
INP üzerindeki etkisini görmek için etkinlik işleyici çalışmasını yeniden düzenlemenin yollarını deneyin.
Önce kullanıcı arayüzünü güncelleyin
js çağrılarının sırasını değiştirirseniz ne olur? Önce kullanıcı arayüzünü güncelleyip ardından engellerseniz ne olur?
Kodun tamamını inceleyin: ui_first.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
blockFor(1000);
});
Kullanıcı arayüzünün daha önce göründüğünü fark ettiniz mi? Sipariş, INP puanlarını etkiler mi?
Herhangi bir fark olup olmadığını görmek için bir iz almayı ve etkileşimi incelemeyi deneyin.
Ayrı dinleyiciler
Çalışmayı ayrı bir etkinlik işleyiciye taşırsanız ne olur? Bir etkinlik işleyicide kullanıcı arayüzünü güncelleyin ve sayfayı ayrı bir işleyiciden engelleyin.
Tam kodu inceleyin: Two_click.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
});
button.addEventListener('click', () => {
blockFor(1000);
});
Bu sekme artık performans panelinde nasıl görünüyor?
Farklı etkinlik türleri
Çoğu etkileşim, işaretçi veya önemli etkinliklerden fareyle üzerine gelme, odaklanma/bulanıklaştırma ve beforechange ve beforeinput gibi sentetik etkinliklere kadar birçok etkinlik türünü tetikler.
Birçok gerçek sayfanın birçok farklı etkinliği işleyicisi vardır.
Etkinlik işleyicileri için etkinlik türlerini değiştirirseniz ne olur? Örneğin, click
etkinlik işleyicilerinden biri pointerup
veya mouseup
ile değiştirilsin mi?
Kodun tamamını inceleyin: diff_handlers.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
});
button.addEventListener('pointerup', () => {
blockFor(1000);
});
Kullanıcı arayüzü güncellemesi yok
Etkinlik işleyiciden kullanıcı arayüzü güncelleme çağrısını kaldırırsanız ne olur?
Kodun tamamını inceleyin: no_ui.html
button.addEventListener('click', () => {
blockFor(1000);
// score.incrementAndUpdateUI();
});
6. İşleme süresiyle ilgili deneme sonuçları
Performans izleme: Önce kullanıcı arayüzünü güncelleyin
Kodun tamamını inceleyin: ui_first.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
blockFor(1000);
});
Düğmeyi tıklamanın Performans paneli kaydına baktığınızda sonuçların değişmediğini görebilirsiniz. Engelleme kodundan önce bir kullanıcı arayüzü güncellemesi tetiklenmiş olsa da tarayıcı, ekranda gösterilen içeriği etkinlik işleyici tamamlanana kadar güncellememiştir. Bu, etkileşimin tamamlanmasının bir saniyeden biraz uzun sürdüğü anlamına gelir.
Performans izleme: ayrı dinleyiciler
Tam kodu inceleyin: Two_click.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
});
button.addEventListener('click', () => {
blockFor(1000);
});
İşlevsel olarak herhangi bir fark yoktur. Etkileşim yine de tam saniye sürüyor.
Tıklama etkileşimini yakınlaştırırsanız click
etkinliğinin sonucunda iki farklı işlevin çağrıldığını görürsünüz.
Beklendiği gibi, ilki (kullanıcı arayüzü güncellemesi) inanılmaz derecede hızlı çalışırken, ikincisi tam saniye sürer. Ancak bunların etkilerinin toplamı son kullanıcı ile aynı yavaş etkileşime neden olur.
Performans izleme: farklı etkinlik türleri
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
});
button.addEventListener('pointerup', () => {
blockFor(1000);
});
Bu sonuçlar çok benzerdir. Etkileşim hâlâ bir saniye sürer; tek fark, yalnızca kullanıcı arayüzü güncellemesi olan daha kısa click
işleyicisinin artık engelleme yapan pointerup
işleyicisinden sonra çalışmasıdır.
Performans izleme: Kullanıcı arayüzü güncellemesi yok
Kodun tamamını inceleyin: no_ui.html
button.addEventListener('click', () => {
blockFor(1000);
// score.incrementAndUpdateUI();
});
- Puan güncellenmez ancak sayfa yine de güncellenir.
- Animasyonlar, CSS efektleri, varsayılan web bileşeni işlemleri (form girişi), metin girişi, vurgulu metinlerin tümü güncellenmeye devam ediyor.
Bu durumda düğme etkin duruma gelir ve tıklandığında geri döner. Bu durumda, tarayıcının boyaması gerekir. Bu da hâlâ bir INP olduğu anlamına gelir.
Etkinlik işleyici, ana iş parçacığını bir saniyeliğine engellediği için sayfanın boyanmasını engellediğinden etkileşim yine de tam bir saniye sürer.
Performans paneli kaydı yapıldığında, etkileşim öncekiyle neredeyse aynı şekilde gösterilir.
Paket servis
Herhangi bir etkinlik işleyicide çalıştırılan herhangi bir kod, etkileşimi geciktirir.
- Bu, bileşen oluşturmayı tetikleyen bir durum güncellemesi gibi farklı komut dosyalarından ve işleyicilerde çalışan çerçeve veya kitaplık kodlarından kaydedilen işleyicileri içerir.
- Yalnızca kendi kodunuzu değil, tüm üçüncü taraf komut dosyalarını da kullanabilirsiniz.
Bu yaygın bir sorundur!
Son olarak: Kodunuzun bir boyamayı tetiklememesi, bir boyamanın yavaş etkinlik işleyicilerin tamamlamasını beklemediği anlamına gelmez.
7. Deneme: Giriş gecikmesi
Etkinlik işleyiciler dışında uzun süre çalışan kod ne olacak? Örneğin:
- Yükleme sırasında sayfayı rastgele engelleyen bir geç yüklenen
<script>
varsa. - Sayfayı düzenli olarak engelleyen
setInterval
gibi bir API çağrısı mı?
blockFor
öğesini etkinlik işleyiciden kaldırıp setInterval()
öğesine eklemeyi deneyin:
Kodun tamamını görün: giriş_delay.html
setInterval(() => {
blockFor(1000);
}, 3000);
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
});
Süreç
8. Giriş gecikmesi deneme sonuçları
Kodun tamamını görün: giriş_delay.html
setInterval(() => {
blockFor(1000);
}, 3000);
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
});
setInterval
engelleme görevi çalışırken gerçekleşen bir düğme tıklamasının kaydedilmesi, etkileşimin kendisinde herhangi bir engelleme işlemi yapılmasa bile uzun süreli bir etkileşimle sonuçlanır.
Bu uzun süreli dönemlere genellikle uzun görevler denir.
Fareyle Geliştirici Araçları'ndaki etkileşimin üzerine geldiğinizde, etkileşim süresinin artık işleme süresiyle değil, giriş gecikmesiyle ilişkilendirildiğini görebilirsiniz.
Unutmayın, bu durum etkileşimleri her zaman etkilemez. Görev çalışırken tıklamazsanız şansınızı kaybedebilirsiniz. Böyle bir "rastgele" hapşırma, ancak bazen sorunlara yol açtığında hata ayıklamak için bir kabus olabilir.
Bunları tespit etmenin yollarından biri, uzun görevleri (veya Uzun Animasyon Karelerini) ve Toplam Engelleme Süresi'ni ölçmektir.
9. Sunu yavaş
Şimdiye kadar, giriş gecikmesi veya etkinlik işleyiciler yoluyla JavaScript'in performansını inceledik, ancak bir sonraki boyama işlemini başka neler etkiler?
Sayfayı da pahalı efektlerle güncellemek.
Sayfa güncellemesi hızlı bir şekilde gelse bile, tarayıcının bunları oluşturmak için yine de çok çalışması gerekebilir.
Ana ileti dizisinde:
- Durum değişikliklerinden sonra güncellemeleri oluşturması gereken kullanıcı arayüzü çerçeveleri
- DOM değişiklikleri veya çok sayıda pahalı CSS sorgu seçicisinin açılıp kapatılması birçok Stil, Düzen ve Boyama işlemini tetikleyebilir.
Ana ileti dizisinden:
- GPU efektlerini desteklemek için CSS kullanma
- Çok büyük, yüksek çözünürlüklü resimler ekleme
- Karmaşık sahneleri çizmek için SVG/Canvas kullanma
Web'de yaygın olarak bulunan bazı örnekler:
- Başlangıçtaki görsel geri bildirim sağlamak için duraklamadan, bir bağlantıyı tıkladıktan sonra DOM'nin tamamını yeniden oluşturan bir SPA sitesi.
- Dinamik bir kullanıcı arayüzüne sahip karmaşık arama filtreleri sunan ancak bunun için pahalı işleyiciler çalıştıran bir arama sayfası.
- Tüm sayfada stili/düzeni tetikleyen koyu mod açma/kapatma düğmesi
10. Deneme: Sunu gecikmesi
requestAnimationFrame
yavaş
Şimdi, requestAnimationFrame()
API'yi kullanarak uzun bir sunum gecikmesi simülasyonu yapalım.
Etkinlik işleyici şunu döndürdükten sonra çalışması için blockFor
çağrısını bir requestAnimationFrame
geri çağırmasına taşıyın:
Kodun tamamını görün: Presentation_delay.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
requestAnimationFrame(() => {
blockFor(1000);
});
});
Süreç
11. Sunum gecikmesi deneme sonuçları
Kodun tamamını görün: Presentation_delay.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
requestAnimationFrame(() => {
blockFor(1000);
});
});
Etkileşim bir saniye kadar uzun kalıyor. Peki ne oldu?
requestAnimationFrame
, bir sonraki boyamadan önce geri aranma isteğinde bulunuyor. INP, etkileşimden bir sonraki boyaya kadar geçen süreyi ölçtüğünden, requestAnimationFrame
içindeki blockFor(1000)
bir sonraki boyayı tam saniye boyunca engellemeye devam eder.
Ancak dikkat edilmesi gereken iki nokta vardır:
- Fareyle üzerine geldiğinizde, tüm etkileşim süresinin artık "sunum gecikmesi"nde harcandığını görürsünüz etkinlik işleyici geri döndükten sonra gerçekleştiği için ana iş parçacığı engellemesi gerçekleşir.
- Ana iş parçacığı etkinliğinin kökü artık tıklama etkinliği değil, "Animasyon Çerçevesi Tetiklendi"dir.
12. Etkileşimleri teşhis etme
Bu test sayfasında puanlar, kronometreler ve sayaç kullanıcı arayüzüyle duyarlılık son derece görseldir. Ancak ortalama bir sayfayı test ederken bu durum daha belirsizdir.
Etkileşimler uzun sürerse nedenin ne olduğu her zaman net olarak anlaşılmayabilir. Hedef:
- Giriş gecikmesi
- Etkinlik işleme süresi
- Sunu gecikmesi?
İstediğiniz sayfada, duyarlılığı ölçmenize yardımcı olması için Geliştirici Araçları'nı kullanabilirsiniz. Bu alışkanlığı kazanmak için şu akışı deneyin:
- Her zamanki gibi web'de gezinin.
- İsteğe bağlı: Web Vitals uzantısı etkileşimleri kaydederken Geliştirici Araçları konsolunu açık bırakın.
- Düşük performans gösteren bir etkileşimle karşılaşırsanız etkileşimi tekrarlamayı deneyin:
- İşlemi tekrarlayamıyorsanız analizler almak için konsol günlüklerini kullanabilirsiniz.
- Tekrar edebiliyorsanız performans panelinde kaydedin.
Tüm gecikmeler
Sayfaya tüm şu sorunlardan birkaçını eklemeyi deneyin:
Kodun tamamını görün: all_the_things.html
setInterval(() => {
blockFor(1000);
}, 3000);
button.addEventListener('click', () => {
blockFor(1000);
score.incrementAndUpdateUI();
requestAnimationFrame(() => {
blockFor(1000);
});
});
Ardından, sorunları teşhis etmek için konsolu ve performans panelini kullanın.
13. Deneme: eşzamansız çalışma
Etkileşimlerin içinde ağ isteklerinde bulunma, zamanlayıcı başlatma veya yalnızca genel durumu güncelleme gibi görsel olmayan efektler başlatabildiğiniz için bunlar sonuçta sayfayı güncellediğinde ne olur?
Bir etkileşimden sonraki bir sonraki boyanın oluşturulmasına izin verildiği sürece, tarayıcı yeni bir oluşturma güncellemesine gerek olmadığına karar verse bile Etkileşim ölçümü durdurulur.
Bunu denemek için tıklama işleyiciden kullanıcı arayüzünü güncellemeye devam edin, ancak engelleme işlemini zaman aşımından çalıştırın.
Kodun tamamını inceleyin: zaman aşımı_100.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
setTimeout(() => {
blockFor(1000);
}, 100);
});
Şimdi ne olacak?
14. Eş zamansız iş denemesi sonuçları
Kodun tamamını inceleyin: zaman aşımı_100.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
setTimeout(() => {
blockFor(1000);
}, 100);
});
Ana iş parçacığı, kullanıcı arayüzü güncellendikten hemen sonra kullanılabilir hâle geldiğinden etkileşim şu anda kısadır. Uzun engelleme görevi hâlâ çalışıyor, yalnızca boyama işleminden bir süre sonra çalışıyor. Bu nedenle, kullanıcı anında kullanıcı arayüzü geri bildirimi alır.
Ders: Kaldıramıyorsanız en azından taşıyın!
Yöntemler
100 milisaniyelik sabit bir setTimeout
değerinden daha iyi olabilir mi? Muhtemelen kodun mümkün olduğunca hızlı çalışmasını istiyoruz, aksi takdirde kodu kaldıracaktınız.
Hedef:
- Etkileşim
incrementAndUpdateUI()
çalıştıracak. blockFor()
en kısa sürede çalışır ancak bir sonraki boyamayı engellemez.- Bu, "sihirli zaman aşımları" olmadan tahmin edilebilir davranışlar sağlar.
Bunu başarmanın bazı yolları şunlardır:
setTimeout(0)
Promise.then()
requestAnimationFrame
requestIdleCallback
scheduler.postTask()
"requestPostAnimationFrame"
requestAnimationFrame
+ setTimeout
, bir sonraki boyamadan önce çalışmayı dener ve genellikle yavaş bir etkileşim oluşturur. Bunun aksine, requestAnimationFrame
+ setTimeout
, requestPostAnimationFrame
için basit bir çoklu dolgu oluşturur ve bir sonraki boyamadan sonra geri çağırmayı çalıştırır.
Kodun tamamını göster: raf+task.html
function afterNextPaint(callback) {
requestAnimationFrame(() => {
setTimeout(callback, 0);
});
}
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
afterNextPaint(() => {
blockFor(1000);
});
});
Ergonomik için bir söz verebilirsiniz:
Kodun tamamını göster: raf+task2.html
async function nextPaint() {
return new Promise(resolve => afterNextPaint(resolve));
}
button.addEventListener('click', async () => {
score.incrementAndUpdateUI();
await nextPaint();
blockFor(1000);
});
15. Birden çok etkileşim (ve yönlendirme tıklamaları)
Engelleme işlemini uzun süre yapmak işe yarayabilir ancak bu uzun görevler yine de sayfayı engeller ve gelecekteki etkileşimlerin yanı sıra diğer birçok sayfa animasyonunu ve güncellemesini etkiler.
Sayfanın eşzamansız engelleme çalışma sürümünü tekrar deneyin (veya son adımda çalışmayı ertelemek için kendi varyasyonunuzu ortaya koyduysanız):
Kodun tamamını inceleyin: zaman aşımı_100.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
setTimeout(() => {
blockFor(1000);
}, 100);
});
Hızlı bir şekilde birden çok kez tıklarsanız ne olur?
Performans izleme
Her tıklama için sırada bir saniyelik uzun bir görev bulunur. Bu sayede, ana iş parçacığı uzun süre boyunca engellenir.
Bu uzun görevler, gelen yeni tıklamalarla çakıştığında, etkinlik işleyici neredeyse anında geri dönse bile yavaş etkileşimlere neden olur. Giriş gecikmeleriyle ilgili önceki denemede de aynı durumu oluşturduk. Ancak bu sefer giriş gecikmesi bir setInterval
kaynağından değil, önceki etkinlik işleyiciler tarafından tetiklenen çalışmadan kaynaklanmaktadır.
Stratejiler
İdeal olarak, uzun görevleri tamamen kaldırmak isteriz.
- Gereksiz kodları, özellikle de komut dosyalarını tamamen kaldırın.
- Uzun görevlerden kaçınmak için kodu optimize edin.
- Yeni etkileşimler geldiğinde eski işi iptal edin.
16. 1. Strateji: Ardışık tekrar
Klasik bir strateji. Etkileşimler art arda hızlı bir şekilde arka arkaya geldiğinde ve işleme ya da ağ etkileri pahalı olduğunda, işlemi bilinçli olarak başlatmayı geciktirerek işlemi iptal edip yeniden başlatabilirsiniz. Bu kalıp, otomatik tamamlama alanları gibi kullanıcı arayüzleri için kullanışlıdır.
- Pahalı işleri (ör. 500-1.000 milisaniye) bir zamanlayıcıyla başlatmayı ertelemek için
setTimeout
kullanın. - Bunu yaparken zamanlayıcı kimliğini kaydedin.
- Yeni bir etkileşim gelirse
clearTimeout
düğmesini kullanarak önceki zamanlayıcıyı iptal edin.
Kodun tamamını inceleyin: debounce.html
let timer;
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
blockFor(1000);
}, 1000);
});
Performans izleme
Birden fazla tıklamaya rağmen yalnızca bir blockFor
görevi çalışır ve çalıştırılmadan önce tam bir saniye boyunca tıklama almayana kadar bekler. Metin girişi yazmak veya birden çok hızlı tıklama alması beklenen öğe hedefleri gibi seri işlemler için bu, varsayılan olarak kullanılacak ideal bir stratejidir.
17. 2. Strateji: uzun süreli işleri kesintiye uğratın
Yine de geri sekmenin süresi dolduktan hemen sonra yeni bir tıklamanın gelmesi, bu uzun görevin ortasına gelmesi ve giriş gecikmesi nedeniyle çok yavaş bir etkileşime dönüşme olasılığı hâlâ düşüktür.
İdeal olarak, bir etkileşim işimizin ortasında gelirse yeni etkileşimlerin hemen ele alınması için yoğun çalışmalarımızı duraklatmak isteriz. Bunu nasıl yapabiliriz?
isInputPending
gibi bazı API'ler vardır ancak uzun görevleri parçalara ayırmak genellikle daha iyidir.
Çok sayıda setTimeout
İlk deneme: Basit bir şey yapın.
Kodun tamamını inceleyin: small_tasks.html
button.addEventListener('click', () => {
score.incrementAndUpdateUI();
requestAnimationFrame(() => {
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
setTimeout(() => blockFor(100), 0);
});
});
Bu özellik, tarayıcının her bir görevi ayrı ayrı planlamasına olanak tanır ve giriş daha yüksek önceliğe sahip olabilir.
Tekrar beş tıklamayla beş saniyelik bir çalışmaya geri dönmüş olduk. Ancak tıklama başına bir saniyelik görev, on adet 100 milisaniyelik göreve bölündü. Sonuç olarak, söz konusu görevlerle çakışan birden fazla etkileşim olsa bile hiçbir etkileşimin 100 milisaniyeden uzun bir giriş gecikmesi olmaz. Tarayıcı, setTimeout
işinde gelen etkinlik işleyicilere öncelik verir ve etkileşimler yanıt vermeye devam eder.
Bu strateji, özellikle ayrı giriş noktaları planlandığında çok işe yarar. Örneğin, uygulamanın yükleme zamanında çağırmanız gereken bir dizi bağımsız özellik varsa işe yarar. Sadece komut dosyalarını yükleyip her şeyi komut dosyası değerlendirme zamanında çalıştırmak varsayılan olarak büyük ve uzun bir görevde her şeyi çalıştırabilir.
Ancak bu strateji, paylaşılan durumu kullanan bir for
döngüsü gibi birbirlerine sıkı sıkıya bağlı kodları ayırmak için de işe yaramaz.
Artık yield()
ile birlikte
Ancak "getiri noktalarını" kolayca eklemek için modern async
ve await
özelliklerinden yararlanabiliriz kullanabilirsiniz.
Örneğin:
Kodun tamamını inceleyin: getiriy.html
// Polyfill for scheduler.yield()
async function schedulerDotYield() {
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
async function blockInPiecesYieldy(ms) {
const ms_per_part = 10;
const parts = ms / ms_per_part;
for (let i = 0; i < parts; i++) {
await schedulerDotYield();
blockFor(ms_per_part);
}
}
button.addEventListener('click', async () => {
score.incrementAndUpdateUI();
await blockInPiecesYieldy(1000);
});
Daha önce olduğu gibi, ana iş parçacığı, bir yığın çalışmadan sonra oluşturulur ve tarayıcı gelen tüm etkileşimlere yanıt verebilir. Ancak artık ayrı setTimeout
yerine bir await schedulerDotYield()
gereken tek şeydir. Bu sayede, for
döngüsünün ortasında bile kullanılabilecek kadar ergonomiktir.
Artık AbortContoller()
ile birlikte
Bu işe yaradı ancak her etkileşim, yeni etkileşimler gelip yapılması gereken işleri değiştirmiş olsa bile daha fazla işin programlanmasını sağlıyor.
Geri döndürme stratejisiyle, her yeni etkileşimde önceki zaman aşımını iptal ettik. Burada da benzer bir şey yapabilir miyiz? Bunu yapmanın bir yolu AbortController()
kullanmaktır:
Kodun tamamını inceleyin: aborty.html
// Polyfill for scheduler.yield()
async function schedulerDotYield() {
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
async function blockInPiecesYieldyAborty(ms, signal) {
const parts = ms / 10;
for (let i = 0; i < parts; i++) {
// If AbortController has been asked to stop, abandon the current loop.
if (signal.aborted) return;
await schedulerDotYield();
blockFor(10);
}
}
let abortController = new AbortController();
button.addEventListener('click', async () => {
score.incrementAndUpdateUI();
abortController.abort();
abortController = new AbortController();
await blockInPiecesYieldyAborty(1000, abortController.signal);
});
Bir tıklama geldiğinde, yapılması gereken işlemi yaparak blockInPiecesYieldyAborty
for
döngüsünü başlatır ve düzenli olarak ana iş parçacığını vererek tarayıcının yeni etkileşimlere yanıt vermeye devam etmesini sağlar.
İkinci bir tıklama geldiğinde, ilk döngü AbortController
ile iptal edildi olarak işaretlenir ve yeni bir blockInPiecesYieldyAborty
döngüsü başlatılır. Bir dahaki sefere ilk döngünün tekrar çalıştırılması planlandığında signal.aborted
değerinin artık true
olduğunu fark eder ve başka bir işlem yapmadan hemen geri döner.
18. Sonuç
Tüm uzun görevleri ayırmak, sitenin yeni etkileşimlere yanıt vermesine olanak tanır. Bu, ilk geri bildirimleri hızlı bir şekilde sağlamanıza ve ayrıca devam etmekte olan işi iptal etmek gibi kararlar almanıza olanak tanır. Bazen bu, giriş noktalarını ayrı görevler olarak planlamak anlamına gelir. Bazen bu, "getiri" eklemek anlamına gelir noktaları belirleyeceğiz.
Unutmayın
- INP tüm etkileşimleri ölçer.
- Her etkileşim, girişten sonraki boyama kadar, yani kullanıcının duyarlılığı görme şekli ölçülür.
- Giriş gecikmesi, etkinlik işleme süresi ve sunum gecikmesinin tümü etkileşimin yanıt verme süresini etkiler.
- INP ve etkileşim dökümlerini Geliştirici Araçları ile kolayca ölçebilirsiniz.
Stratejiler
- Sayfalarınızda uzun süreli kod (uzun görevler) olmamalıdır.
- Bir sonraki boyama sonrasına kadar gereksiz kodu etkinlik işleyicilerin dışına taşıyın.
- Oluşturma güncellemesinin tarayıcı için verimli olduğundan emin olun.