INP nasıl düzeltilir? Etkileşim gecikmesinin sebepleri ve çözümleri

Kullanıcı bir butona tıklıyor, sayfa bir süre donuk kalıyor, sonra tepki veriyor. Lighthouse puanı yüksek görünse bile Search Console'da INP uyarısı geliyorsa sorun tam olarak budur: ana iş parçacığı (main thread) o anda başka işle meşgul.

INP, Mart 2024'te FID'in yerini aldı ve FID'den çok daha zor bir metrik. Sadece ilk etkileşimi değil, sayfa ömrü boyunca yapılan etkileşimleri izliyor. Bu yüzden "ilk yüklemede JavaScript'i ertele" gibi eski taktikler tek başına yetmiyor.

INP tam olarak neyi ölçüyor?

INP (Interaction to Next Paint), bir tıklama, dokunma veya klavye etkileşimi ile tarayıcının bir sonraki kareyi ekrana çizmesi arasındaki süreyi ölçer. Kaydırma ve üzerine gelme (hover) sayılmaz. Sayfa kapanırken en yavaş etkileşimlerden biri raporlanır; çok sayıda etkileşim olan sayfalarda tek tük aykırı değerler hesaptan düşülür. Kısacası INP, "en kötüye yakın" etkileşimi temsil eder.

Her etkileşim üç parçadan oluşur:

  • Giriş gecikmesi (input delay): Kullanıcı tıkladı ama ana iş parçacığı başka bir görevi bitirmeden olay işleyicisi çalışamıyor.
  • İşleme süresi (processing duration): Olay işleyicilerinizin (click, keydown vb.) çalıştığı süre.
  • Sunum gecikmesi (presentation delay): İşleyiciler bittikten sonra stil hesaplama, layout ve paint ile yeni karenin ekrana gelmesi.

Hangi parçanın büyük olduğunu bilmeden düzeltme yapmak, karanlıkta ok atmaktır. Giriş gecikmesi büyükse sorun başka bir script'tir; işleme süresi büyükse sizin kodunuzdur; sunum gecikmesi büyükse DOM ve render maliyetidir.

Eşikler ve saha verisi

INP değeriDeğerlendirme
200 ms ve altıİyi
200-500 msİyileştirme gerekli
500 ms üstüKötü

Değerlendirme gerçek kullanıcıların 75. yüzdeliğine göre yapılır (CrUX verisi). Yani ziyaretçilerin dörtte üçünün deneyimi 200 ms'nin altında olmalı.

Burada önemli bir ayrım var: INP bir saha (field) metriğidir. Laboratuvar testinde kimse tıklamadığı için Lighthouse INP ölçemez. Laboratuvarda en yakın vekil TBT'dir (Total Blocking Time). TBT yüksekse INP'nin de kötü olma ihtimali yüksektir, ama TBT'nin iyi olması INP'nin iyi olduğunu garanti etmez; çünkü INP, yükleme bittikten çok sonra yapılan etkileşimlerde de bozulabilir.

Yavaş etkileşimleri bulmak

Ben şu sırayla ilerliyorum:

  1. Search Console > Önemli Web Verileri (Core Web Vitals) raporu: Hangi URL gruplarında INP sorunu olduğunu gösterir. Mobil ve masaüstü ayrı raporlanır.
  2. PageSpeed Insights: Tek bir URL veya tüm origin için CrUX saha verisini gösterir. Yeterli trafik yoksa veri çıkmaz.
  3. web-vitals kütüphanesi (attribution sürümü): Gerçek kullanıcılardan hangi elemanın, hangi etkileşim türünün ve hangi fazın yavaş olduğunu toplar. Asıl teşhis burada yapılır.
  4. Chrome DevTools > Performance paneli: Şüpheli etkileşimi kendi makinenizde CPU yavaşlatma (throttling) açıkken kaydedip hangi fonksiyonun ana iş parçacığını tuttuğunu görürsünüz. Güncel sürümlerde panel, siz sayfayla etkileşirken yerel INP değerini canlı olarak da gösteriyor.

web-vitals kütüphanesinin attribution sürümüyle en basit kurulum şöyle:

inp-log.js
import { onINP } from 'web-vitals/attribution';

onINP((metric) => {
  const a = metric.attribution;
  // Toplam değer ve derecelendirme (good / needs-improvement / poor)
  console.log('INP:', Math.round(metric.value), 'ms', metric.rating);
  // Hangi eleman ve hangi etkileşim türü
  console.log('Hedef:', a.interactionTarget, '| Tür:', a.interactionType);
  // Üç fazın dağılımı
  console.log('Giriş gecikmesi:', Math.round(a.inputDelay), 'ms');
  console.log('İşleme süresi:', Math.round(a.processingDuration), 'ms');
  console.log('Sunum gecikmesi:', Math.round(a.presentationDelay), 'ms');
}, { reportAllChanges: true });

Konsola yazmak geliştirme için yeterli. Canlıda bu veriyi navigator.sendBeacon() ile kendi uç noktanıza gönderip interactionTarget değerine göre gruplamak, hangi butonun veya menünün sorunlu olduğunu birkaç gün içinde netleştirir. Ücretli bir RUM aracına gerek yok; küçük bir PHP betiği ve bir tablo yeterli.

En sık görülen sebepler

  • Uzun görevler (long tasks): 50 ms'den uzun süren her JavaScript görevi ana iş parçacığını kilitler. Tıklama o sırada gelirse beklemek zorunda kalır.
  • Ağır üçüncü parti script'ler: Etiket yöneticileri, sohbet widget'ları, reklam ve A/B test script'leri kendi zamanlamalarıyla çalışır ve giriş gecikmesini şişirir.
  • Büyük DOM: Binlerce düğümlü bir sayfada küçük bir sınıf değişikliği bile pahalı stil ve layout hesaplamasına yol açar. Bu, sunum gecikmesinde görünür.
  • Hydration: React, Vue gibi framework'lerde sayfa sunucudan gelir ama etkileşimli hale gelmesi için tüm bileşenlerin istemcide yeniden bağlanması gerekir. Bu sırada yapılan tıklamalar bekler.
  • Zorunlu senkron layout: Bir döngüde önce stil yazıp hemen ardından offsetHeight gibi bir ölçüm okumak, tarayıcıyı her adımda layout hesaplamaya zorlar (layout thrashing).

Çözümler

Uzun görevleri bölmek ve ana iş parçacığına yol vermek

En etkili teknik, işi parçalara ayırıp aralarda tarayıcıya nefes aldırmaktır. scheduler.yield() bunun için tasarlandı; desteklemeyen tarayıcılarda setTimeout ile geri düşüyoruz:

yield.js
// Ana iş parçacığına kontrolü geri verir
function yieldToMain() {
  if (globalThis.scheduler?.yield) {
    return scheduler.yield();
  }
  return new Promise((resolve) => setTimeout(resolve, 0));
}

// Büyük listeyi 50 ms'lik dilimler halinde işler
async function processItems(items, handleItem) {
  let lastYield = performance.now();
  for (const item of items) {
    handleItem(item);
    if (performance.now() - lastYield > 50) {
      await yieldToMain();
      lastYield = performance.now();
    }
  }
}

// Önce görsel geri bildirim, sonra ağır iş
const button = document.querySelector('#filtrele');
button.addEventListener('click', async () => {
  button.classList.add('yukleniyor');
  await yieldToMain();
  applyFilters(); // ağır filtreleme fonksiyonunuz
});

Son örnekteki desen önemli: kullanıcıya hemen bir tepki gösterip (buton durumu, spinner) ağır işi bir sonraki göreve bırakırsanız, bir sonraki kare hemen çizilir ve INP düşer. İş yine yapılır, ama kullanıcı bekletilmez.

Debounce ve gereksiz işi azaltmak

Arama kutusunda her tuş vuruşunda filtreleme veya istek yapmak klasik bir INP katilidir. Tuş vuruşunu hemen ekrana yansıtın, pahalı işi 200-300 ms'lik bir debounce ile geciktirin. Aynı mantık resize ve input olayları için de geçerli.

İşi ana iş parçacığından çıkarmak

Veri işleme, sıralama, büyük JSON ayrıştırma gibi DOM'a dokunmayan işler Web Worker'a taşınabilir. Worker ayrı bir iş parçacığında çalışır; ana iş parçacığı etkileşimlere açık kalır.

DOM'u küçültmek

Görünmeyen menü ağaçlarını, sekmelerin içindeki devasa listeleri ilk yüklemede DOM'a koymamak veya sayfalamak sunum gecikmesini doğrudan azaltır. Ekran dışı büyük bölümler için CSS content-visibility: auto da işe yarar. Layout thrashing için kural basit: önce tüm ölçümleri okuyun, sonra tüm yazma işlemlerini yapın.

Üçüncü parti script'leri ertelemek

Her script'i tek tek sorgulayın: gerçekten her sayfada mı gerekli? Sohbet widget'ını kullanıcı ilk etkileşimde veya birkaç saniye sonra yüklemek, etiket yöneticisindeki ölü etiketleri temizlemek, A/B test script'ini sadece test yapılan sayfalara koymak çoğu zaman kod yazmaktan daha fazla kazandırır.

Hydration maliyetini düşürmek

Framework kullanıyorsanız, etkileşim gerektirmeyen bölümleri statik bırakmak (kısmi veya ada tipi hydration), büyük bileşenleri tembel yüklemek ve istemciye giden JavaScript miktarını azaltmak gerekir. SSR ve SSG seçenekleri için React/Vue sitelerinde SEO: SSR, SSG, prerender yazısına bakabilirsiniz.

INP ve SEO ilişkisi hakkında dürüst bir not

Core Web Vitals, Google'ın sayfa deneyimi sinyallerinin bir parçası; ama alakalı ve iyi içeriğin yerini tutmaz. INP'yi 350 ms'den 180 ms'ye indirmek tek başına sıralamayı uçurmaz. Buna karşın takılan bir sayfa kullanıcıyı gerçekten kaçırır; özellikle filtreli kategori sayfaları ve formlar dönüşümü doğrudan etkiler. Ben INP'yi önce kullanıcı sorunu, sonra SEO sinyali olarak görüyorum.

Diğer iki metrik için LCP'yi 2,5 saniyenin altına indirmek ve CLS: sayfa kaymasını sıfırlamak yazılarına da göz atın. Google'ın metrik tanımı için web.dev INP sayfası güvenilir kaynak.

Kontrol listesi

  • Search Console Önemli Web Verileri raporunda INP sorunlu URL gruplarını belirledim.
  • web-vitals attribution ile gerçek kullanıcılardan hedef eleman ve faz verisini topluyorum.
  • Hangi fazın (giriş, işleme, sunum) baskın olduğunu biliyorum.
  • 50 ms'den uzun görevleri scheduler.yield() veya setTimeout ile böldüm.
  • Tıklamada önce görsel geri bildirim, sonra ağır iş prensibini uyguladım.
  • Arama ve filtre girişlerine debounce ekledim.
  • Üçüncü parti script'lerin listesini çıkarıp gereksizleri kaldırdım veya erteledim.
  • DOM boyutunu ve layout thrashing yapan kodları gözden geçirdim.
  • Değişikliklerden sonra saha verisinin güncellenmesi için 28 günlük CrUX penceresini beklemem gerektiğini biliyorum.

Comments / questions

If you have a question about any topic or wish to contact me: Telegram or send an email to [email protected] Thanks!

Related pages