INP masaüstünde iyi ama mobilde kötü çıkıyorsa sorun donanım kısıtlaması, touch event handler gecikmesi veya uzun JavaScript görevlerinden biridir. Platform asimetrisinin arkasındaki mekanizmalar etkileşim profili üzerinden ayırt edilir.

INP Mobilde Kötü Masaüstünde İyi: Hangi Event Probleme Yol Açıyor?

INP (Interaction to Next Paint), bir kullanıcının tıklama, dokunma veya klavye etkileşiminin ardından tarayıcının ekranı ne kadar sürede güncellediğini ölçer. Masaüstünde 100 milisaniyenin altında kalan bu değer, aynı sayfada, aynı kod tabanında mobil cihazlarda 400-600 milisaniyeye çıkabilir. Durumu daha da kafa karıştırıcı yapan şey şudur: Lighthouse skoru her iki platformda da yüksek olabilir, çünkü Lighthouse yalnızca sayfa yüklemesini ölçer ve yükleme sonrası etkileşimlere bakmaz.

Platform asimetrisi "cihaz farkı" diye geçiştirilebilecek bir durum değildir. Aynı JavaScript aynı mantığı çalıştırır; ancak farklı donanımlarda farklı sürelerde biter. Bu fark, kodunuzda belirli bir müdahale noktasını işaret eder. Masaüstünde sorun görünmüyorsa render bloğu veya ağ gecikmesi değil, CPU işleme kapasitesi, touch event handler gecikmesi veya main thread kilitlenmesi söz konusudur.

Masaüstünde iyi, mobilde kötü INP tablosunun ardında donanım kısıtı, touch event zinciri ve uzun görev kombinasyonu durur; bu nedenleri etkileşim profili üzerinden ayırmadan yapılan düzeltme çoğu zaman yanlış katmanı hedefler. Tanılama sırası burada belirleyicidir.

Donanım kısıtlaması INP asimetrisini nasıl yaratır?

Mobil cihazlar heterojen bir segment oluşturur. Üst segment akıllı telefonlar masaüstü performansına yaklaşabilir; orta ve alt segment cihazlar ise çok daha kısıtlı CPU kapasitesiyle çalışır. INP sorunları bu ikinci grupta yoğunlaşır. JavaScript ayrıştırma, stil yeniden hesaplama ve layout işlemleri, masaüstünde 8 ms süren bir görevi bu cihazlarda 35-50 ms'ye çıkarabilir. Üstelik uzun süreli kullanımda thermal throttling devreye girerek CPU frekansı düşer; soğuyan cihazda performans toparlanır, ama bu bir çözüm değildir.

INP'nin tam ölçtüğü şey şudur: etkileşim başladıktan sonra tarayıcının main thread'i temizleyip ekranı yenilediği süre. Masaüstünde main thread bir görevi hızla bitirdiği için etkileşim sonrası boya kısa sürede gelir. Mobil cihazda aynı main thread daha uzun süre meşgul kalır; bu pencere içinde gelen etkileşim kuyruğa girer ve INP değeri yükselir.

Bunu doğrulamanın pratik yolu, Chrome DevTools Performance sekmesinde CPU kısıtlamasını 4x olarak ayarlayıp profil almaktır. Masaüstünde 40 ms olan bir task, 4x kısıtlamayla 160 ms'ye çıkıyorsa orta segmentli bir mobil cihazda benzer bir değer beklenir. Flame chart'ın gösterdiği göreve bakın; profil, sorunun belirli bir kod bloğunda mı yoksa genel CPU kapasitesinde mi kilitlendiğini netleştirir ve bu iki durum farklı müdahale gerektirir.

Touch event handler'larının masaüstünde görünmeyen gecikmesi

Mobil etkileşimler bir event zincirinden geçer: touchstart, touchend, ardından sentezlenen click. Bu zincirin kendisi INP'ye önemli bir gecikme eklemez; ancak passive olmayan touch listener'lar tarayıcıyı durdurur. Passive olmayan bir touchstart listener gördüğünde tarayıcı, handler'ın preventDefault() çağırıp çağırmadığını bilmeden kaydırma kararını veremez ve handler bitmesini bekler.

Handler 60 ms sürüyorsa bu sürenin tamamı INP'ye eklenir. Masaüstünde aynı kod çalışır, ama mousedown/mouseup üzerinden geçtiği için bu gecikme birikmez. Asimetri tam buradan kaynaklanır: kod aynı, ama event zinciri farklıdır.

Sorun her zaman doğrudan sizin yazdığınız koddan gelmeyebilir. Eski jQuery sürümleri ve bazı analitik kütüphaneleri passive olmayan touchstart listener ekler. DevTools'un Elements sekmesindeki Event Listeners panelini açıp touchstart satırını genişletin; "Passive" sütununu kontrol edin. Passive olmayan her listener potansiyel bir gecikme kaynağıdır. Lab skoruyla gerçek kullanıcı deneyimi arasındaki farkı ele alan yazı, bu tür görünmez gecikmelerin neden standart ölçümlerde çoğunlukla atlandığını açıklar.

Büyük JavaScript bloğu main thread'i nasıl kilitler?

INP'yi artıran en yaygın mekanizma uzun görevlerdir (long tasks). Bir görev 50 ms'yi aşarsa tarayıcı o süre boyunca kullanıcı girişine yanıt veremez. Etkileşim kuyruğa girer, görev biter, ardından işlenir. Masaüstünde 55 ms'lik bir görev, CPU hızı sayesinde etkileşim sonrası boyanın 100 ms eşiğinin altında kalmasını sağlayabilir; mobil cihazda aynı görev 150 ms'ye uzar ve etkileşim bu pencereye denk gelirse INP 200 ms'yi kolayca aşar.

Profil alırken dikkat edilecek şey şudur: uzun görev çubuğu ile ardından gelen etkileşim bloğu arasındaki ilişki. Etkileşim, uzun görevin içine düşüyorsa gecikme orada birikiyor demektir. Flame chart bu görevin içinde hangi fonksiyonların çalıştığını gösterir; framework reaktivite döngüsü, route geçişi veya büyük bir veri işleme bloğu en sık rastlanan kaynaklardır.

Kısa görünebilir. Ama bir etkileşim handler'ı tek başına hafif olsa bile tetiklediği re-render veya hesaplama zincirine baktığınızda uzun task ortaya çıkabilir; bu durumda handler'ı optimize etmek yeterli gelmez, render kapsamını daraltmak veya ağır hesaplamayı defer etmek gerekir. İki ayrı sorun, iki ayrı çözüm.

DevTools ile etkileşim profilini adım adım okumak

INP tanılamasında Lighthouse tek başına yeterli değildir. Lighthouse sayfayı yükler ve biter; yükleme sonrası etkileşimleri ölçmez. Bunun için Performance paneli veya gerçek kullanıcı ölçümü (RUM) kullanılır.

DevTools'ta şu adımları izleyin: Performance sekmesini açın, CPU kısıtlamasını 4x olarak ayarlayın, kaydı başlatın. Sayfa tamamen yüklenene kadar bekleyin, ardından sorunlu etkileşimi gerçekleştirin; tıklama, form girişi veya menü açma. Kaydı durdurun. Interactions track'te etkileşim bloklarını arayın; her bloğun başlangıcından bir sonraki boyamaya kadar geçen süre o etkileşimin INP değerini temsil eder.

Hangi handler'ın uzun sürdüğünü bulmak için etkileşim bloğunun üzerine tıklayın ve call stack'i inceleyin. onClick içinde 30 ms'lik bir state güncellemesi varsa ve bu güncelleme 80 ms'lik bir re-render tetikliyorsa, gecikmenin büyük kısmı render tarafındadır. Performans sorununu tanılarken sıralamanın önemine dair yazı, flame chart okumalarını INP dışındaki metriklerle nasıl ilişkilendireceğinizi de ele alır.

Hangi event'in probleme yol açtığını PerformanceObserver ile tespit etmek

Platform asimetrisi her zaman tek bir event'e bağlı değildir. Birden fazla mekanizma aynı anda devrede olabilir: büyük bir uzun görev, passive olmayan bir touch listener ve ağır bir re-render. Bu durumda INP profili birkaç kaynaktan gelen gecikmeleri bir arada içerir.

Kaynakları ayırt etmek için PerformanceObserver ile event tipini dinleyip gecikmeyi üç bileşene bölmek işe yarar. Input delay, processingStart - startTime arasındaki süredir: bu yüksekse main thread etkileşim sırasında meşguldü. Processing time, processingEnd - processingStart arasındaki süredir: bu yüksekse handler'ın kendisi ağırdır. Presentation delay ise kalan kısımdır; bu yüksekse boyama aşaması uzun sürmüştür.

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    const inputDelay = entry.processingStart - entry.startTime;
    const processingTime = entry.processingEnd - entry.processingStart;
    const presentationDelay =
      entry.duration - processingTime - inputDelay;
    console.log({
      type: entry.name,
      inputDelay,
      processingTime,
      presentationDelay,
    });
  }
}).observe({ type: "event", buffered: true, durationThreshold: 40 });

Bu üç değer, hangi katmanın baskın olduğunu gösterir. Input delay baskınsa etkileşim anında main thread'de uzun bir görev çalışıyordur; göreve odaklanın. Handler processing time baskınsa, callback fonksiyonunun kendisi optimize edilmelidir. Presentation delay baskınsa, layout thrashing veya büyük bir DOM güncellemesi olasıdır. Tek sayı olan INP değerinden bakıldığında üç sorun birbirinden ayırt edilemez; bu yüzden bileşen bazlı ölçüm gerekir.

Asimetrik INP profilinde sık karşılaşılan örüntüler

Masaüstünde iyi, mobilde kötü tablosunda en çok rastlanan ilk örüntü: touchstart üzerine eklenmiş debounce edilmemiş hesaplamalar. scroll olayı masaüstünde passive olarak işlenir; touchstart ise mobilde özgüdür. Hesaplama her iki platformda da çalışır, ama masaüstünde yalnızca scroll üzerinden geçerken mobilde hem scroll hem de touchstart zincirini tetikler; sonuç, mobilde iki kez çalışan ve birinin passive olmadığı bir hesaplamadır.

İkinci örüntü, framework'e bağlı reaktivite maliyetidir. Kullanıcı bir input alanına yazdığında her tuş basışı state güncellemesi tetikler; bu güncelleme büyük bir component ağacını yeniden render eder. Masaüstünde render 25 ms sürebilir ve INP eşiğinin altında kalır. Mobilde aynı render 80-100 ms'ye uzar ve her tuş basışı sorunlu bir etkileşim haline gelir. Bu durumu DevTools'ta tanımak kolaydır: flame chart'ta tuş basışının hemen ardından gelen uzun bir render ağacı görürsünüz. Çözüm genellikle state güncelleme sıklığını sınırlamak ya da render kapsamını daraltmaktır.

Üçüncü örüntü, lazy load edilen modüllerin geç ayrıştırılmasıdır. Bir düğmeye ilk tıklandığında kod çalıştırılmadan önce bir modül indirilip ayrıştırılır. Masaüstünde bu ayrıştırma 15 ms sürer; mobilde 60-80 ms. İlk etkileşim INP'yi yükseltir, sonraki etkileşimler normaldir. Framework tabanlı projelerde darboğaz tespitini ele alan yazı, bu tür geç modül yüklemelerinin neden özellikle bileşen bazlı mimarilerde sık görüldüğünü açıklar.

Düzeltme sırası: hangi katmana önce müdahale edilir?

INP düşürmek için yapılan müdahaleler bazen işe yaramaz, çünkü yanlış katmanı hedef alır. Input delay yüksekse uzun görevleri kırın; setTimeout veya scheduler.yield() ile görev zincirine ara verin. Etkileşim kuyruğa girmeden önce main thread boşaltılmalıdır. Bu adım processing time'ı etkilemez, yalnızca kuyruktaki beklemeyi azaltır.

Processing time yüksekse handler fonksiyonunun kendisini optimize edin: gereksiz DOM sorgularını önbelleğe alın, senkron layout tetikleyen okuma-yazma karışıklığını giderin (layout thrashing), ağır hesaplamayı Web Worker'a taşıyın. Küçük. Net. Ve yalnızca bu katmana odaklanın.

Presentation delay yüksekse render kapsamını daraltın. Büyük bir DOM güncellemesi yerine yalnızca değişen alanı hedefleyin; CSS contain özelliği ve content-visibility bu noktada işe yarar. Render zinciri sorunlarını ele alan yazı bu optimizasyonların sayfa yükleme süresiyle ilişkisini de gösterir. Aylık metrik takibi kurmaya dair rehber ise INP değişikliklerini deploy sonrasında izlemenin nasıl sistematik hale getirileceğini aktarır.

Hangi katmanda sorun olduğunu bilmeden müdahale etmek, genellikle gereksiz kod karmaşıklığı yaratır ve INP değerini düşürmez. Üç bileşeni ölçün, en yüksek olanı hedefleyin.

INP'nin mobilde kötü, masaüstünde iyi çıkması kendi başına bir tanı koydurmaz; yalnızca sorunun CPU kapasitesiyle ilgili bir katmanda olduğuna işaret eder. Donanım kısıtlaması, touch event zinciri ve uzun görev kombinasyonu birbirinden bağımsız sorunlardır ve her biri farklı bir yerde görünür. Flame chart okumadan ve bileşen bazlı ölçüm yapmadan başlanan düzeltme, doğru noktayı bulmak yerine deneme-yanılma sürecine dönüşür.

Somut tanılama sırası şöyle kurulabilir: önce CrUX veya RUM verisiyle mobil INP değerini doğrulayın, ardından DevTools'ta 4x CPU kısıtlamasıyla sorunlu etkileşimi kaydedin, bileşen bazlı ölçümle hangi katmanın baskın olduğunu belirleyin ve o katmana özgü müdahaleyi uygulayıp ölçümü tekrarlayın. Her adım önceki adımın sonucuna dayanır; sırayı atlamak tanılamayı değil tahmini üretir.

Platform asimetrisi, özellikle touch-first etkileşimlerin yoğun olduğu sayfalarda göz ardı edilmesi kolay bir sinyaldir. Masaüstünde her şey yolunda görünür; gerçek kullanıcının cihazı ise farklı bir tablo ortaya koyar. Alan verisi ile lab verisi arasındaki bu tür asimetrilerin başka metriklerde de nasıl ortaya çıktığını gösteren yazı bu tanılama mantığını tamamlayıcı bir açıdan ele alır.