Ana içeriğe geç

TTI (Time to Interactive) Nedir? Etkileşime Hazır Süresi

TTI Time to Interactive Nedir - Teknik SEO Rehberi

Sayfa ekranda tamamen belirdi, metin okunabilir, görseller yüklendi. Kullanıcı menüye tıklıyor ama hiçbir şey olmuyor. Tekrar tıklıyor; yine yok. Birkaç saniye sonra bütün tıklamalar aynı anda işleniyor ve sayfa beklenmedik biçimde zıplıyor. Bu deneyim, FCP ve LCP'nin başarılı gösterdiği bir sayfada kolaylıkla yaşanabilir. TTI (Time to Interactive) tam bu boşluğu ölçer.

Görsel yükleme ile etkileşime hazırlık birbirinden bağımsız iki süreçtir. Biri tamamlanmadan diğerinin tamamlandığı görünümü verilebilir; bu da performans ölçümünde en çok atlanan yanılgılardan biridir.

TTI tam olarak hangi anı ölçer

Time to Interactive, sayfanın hem görsel olarak makul biçimde yüklendiği hem de main thread'in uzun süre bloke olmayacak duruma geldiği ilk anı yakalar. Bunun için belirli bir algoritma çalışır: FCP'den itibaren ileriye bakılır ve main thread'de 50 milisaniyeyi aşan görev (long task) bulunmayan, kesintisiz 5 saniyelik bir pencere aranır. Bu sessiz pencere bulununca geriye gidilir ve en son tamamlanan uzun görevin bitiş zamanı TTI olarak belirlenir.

50 milisaniye eşiği burada da geçerli çünkü bu süre, algısal psikolojide bir eylemin "anlık" hissettirdiği sınırdır; üstündeki gecikmeler kullanıcı tarafından ağırlık olarak hissedilir. 5 saniyelik sessiz pencere ise sayfanın gerçekten boşta kaldığını, yani başka büyük işler sırada beklemediğini kanıtlar.

Bir ayrıntı atlanmamalı: TTI, kullanıcının sayfaya geldiği andan değil, FCP'den itibaren ölçülür. Sayfa yavaş açılıyorsa ve FCP geç geldiyse TTI her halükarda ondan sonra gelir. İki metriği birbirinden bağımsız değerlendirmek yanıltıcı olabilir.

FCP ve LCP ile ilişkisi: üç farklı an

FCP, ilk içerik biriminin ekrana çizildiği andır; sayfanın tamamen boş olmadığını kanıtlar. LCP, en büyük içerik unsurunun yüklendiği andır; sayfanın esas içeriğinin hazır olduğunu gösterir. TTI ise main thread'in gerçekten boş kaldığı, kullanıcı girişinin işlenebileceği andır.

Üçü sırayla gelir ama aralarındaki fark sıfır olabilir ya da saniyeler boyunca açık kalabilir. Bir blog sayfasını ele alalım: HTML şablonu hızlı yüklenir, LCP iki saniyede tamamlanır. Ancak sayfanın altında 400 KB'lık analitik ve pazarlama scriptleri main thread'i meşgul etmeye devam ediyorsa TTI 7-8 saniyeye çıkabilir. Google PageSpeed bu durumu LCP üzerinden iyi bir puan olarak yansıtırken TBT ve TTI üzerinden ciddi ceza keser.

FCP ve LCP'nin hangi bağlamda ortaya çıktığını, Core Web Vitals ekosistemi içindeki yerlerini daha geniş bir çerçevede görmek için Core Web Vitals'ın genel yapısını anlatan yazı bu ilişkileri toplu olarak ele alıyor.

Lighthouse'daki ağırlık değişikliği

TTI, uzun süre Lighthouse'un performans puanına katkı sağlayan altı metrikten biriydi. Lighthouse 10 ile bu ağırlık sıfıra indi. TTI artık Lighthouse raporlarında görünüyor ama puan hesabını etkilemiyor.

Problem hâlâ var; metrik sadece değişti.

Yerine geçen TBT'dir. Lighthouse, main thread'in bloke olma süresini TBT aracılığıyla ölçmeye devam ediyor ve puanın önemli bir bölümü oradan geliyor. TTI ile TBT arasında kavramsal bir örtüşme var: her ikisi de uzun JavaScript görevlerine karşı hassas. Ancak TBT birikmeli bir süreyi ölçerken TTI tek bir zaman damgası üretiyor. Birikim ile zaman damgasının farkı, sorunu teşhis ederken farklı araçlar gerektiriyor; TBT hangi görevlerin ne kadar süre bloke ettiğini anlamak için daha kullanışlı, TTI ise kullanıcının sayfayı ne zaman gerçekten kullanabildiğini anlatıyor. TBT'nin uzun görev mantığını ve ölçüm davranışını ayrı bir yazıda inceledik.

INP ise farklı bir kategoride değerlendirilmeli: CrUX verisiyle gerçek kullanıcı etkileşimlerini ölçüyor ve Mart 2024'ten bu yana bir Core Web Vital olarak FID'in yerini aldı. TTI laboratuvar ortamında yapay senaryo üretirken INP gerçek etkileşim gecikmelerini yakalar. Birinin iyi olması diğerini garanti etmez; bu ikisi aynı sorunun iki farklı ölçüm açısıdır.

Yüksek TTI'ye yol açan asıl nedenler

Main thread'i bloke eden her şey TTI'yi uzatır. Bunu söylemek kolay ama pratikte hangi kaynak bloke ediyor sorusu genellikle yanıtsız kalıyor. Üç kategori öne çıkıyor.

Büyük ve senkron JavaScript dosyaları en belirgin kaynaktır. Özellikle <head> içine yazılmış, async veya defer almamış scriptler tarayıcıyı durdurur. 200-300 KB'lık parse edilmemiş JavaScript, düşük ve orta segment cihazlarda fark edilir biçimde TTI'yi geç getirebilir; mobilde parse maliyeti masaüstünden iki ila üç kat daha uzun sürebilir.

Üçüncü taraf scriptler ikinci sık nedendir. Chat widget'ları, ısı haritası kütüphaneleri, pazarlama otomasyon araçları ve A/B test scriptlerinin önemli bir kısmı main thread üzerinde ağırlık oluşturur. Bu kaynaklar sayfa sahibinin doğrudan kontrolünde olmadığı için de kolayca gözden kaçar. Lighthouse'un "Third-party usage" raporu bu kaynakları ayrıştırmak için başlangıç noktasıdır.

Çok uzun tek JavaScript görevleri üçüncü kategoridir. Beş adet 60ms'lik görev ile tek bir 300ms'lik görev aynı TBT değerini üretebilir ama TTI üzerindeki etkisi farklıdır; uzun tek görev 5 saniyelik sessiz pencereyi her seferinde sıfırlar. Bu nedenle büyük görevleri parçalamak, yani setTimeout(0) veya scheduler.yield() ile main thread'e nefes aldırmak, TTI açısından TBT'yi düşürmekten daha doğrudan bir etki üretir.

Framework tabanlı uygulamalarda ayrı bir kaynak daha devreye girer: hydration maliyeti. React, Vue veya Angular ile geliştirilmiş sayfalarda sunucu tarafı render edilmiş HTML hızla gelir, ekran dolmuş görünür; ancak JavaScript bundle yüklenip parse edilip çalışana kadar sayfanın hiçbir olay dinleyicisi aktif değildir. Bu süre boyunca kullanıcı tıklıyor ama yanıt gelmiyor. TTI tam bu gecikmeli başlatma anını yakalar. 500 KB'ı aşan framework bundle'ları orta segment Android cihazlarda 2-4 saniyelik hydration gecikmesi üretebilir; bu cihazlar Lighthouse'un 4x CPU throttling simülasyonunun hedef aldığı kategoridir.

TTI'yi iyileştirmek için hangi adımlar atılabilir

Main thread'e gelen yükü azaltmak ya da geciktirmek bu metriği doğrudan etkiler. Bunu üç ayrı katmanda düşünmek daha verimli bir yaklaşım.

İlk katman: JavaScript hacmini azaltmak. Kullanılmayan kod, gereksiz polyfill'ler ve aşırı büyük bağımlılıklar parse maliyeti oluşturur. JS ve CSS dosyalarını küçültmek başlangıç noktasıdır ama yalnızca başlangıçtır; asıl etki bundle analizi ile kullanılmayan bağımlılıkları bulmaktan ve çıkarmaktan gelir. Tree shaking ile dead code elimination bu aşamada devreye girer.

İkinci katman: kritik olmayan JavaScript'i ertelemek. Yalnızca sayfa etkileşimi başladıktan sonra gereken scriptler defer veya dinamik import() ile yüklenebilir. Kaydırma animasyonu, lazy load mantığı, chat widget başlatma, A/B test kodları; bunların tamamının sayfa açılır açılmaz main thread'i meşgul etmesi gerekmez. Sayfa ilk yüklenmesinde hangi JavaScript'in gerçekten zorunlu olduğunu belirlemek bu noktada yapılacak en değerli analiz.

Code splitting bu katmanın teknik karşılığıdır. Tüm uygulamayı tek bir bundle olarak göndermek yerine, route veya bileşen bazında bölme yapıldığında ilk yüklemede yalnızca o sayfanın ihtiyaç duyduğu kod gönderilir. webpack, Rollup veya Vite ile yapılandırılan otomatik code splitting bu işlemi büyük ölçüde devre dışı bırakır. Ancak code splitting kendi trade-off'unu beraberinde getirir: kullanıcı yeni bir bölüme geçtiğinde o parçanın yüklenmesi için ek bir ağ isteği gerekir. Dolayısıyla tek seferlik uzun yükleme yerine her bölüm geçişinde küçük gecikmeler üretilmiş olur; hangisinin daha az sorun yarattığı, uygulamanın kullanım akışına bağlıdır.

Üçüncü katman: uzun görevleri bölmek. Bir işlemin 200-300ms süren tek bir fonksiyon olması zorunlu değil. Aynı hesaplama küçük bloklara bölünüp aralarında main thread'e nefes aldırılabilir. Bu özellikle büyük listeler filtreleyen, karmaşık hesaplamalar yapan veya DOM'u toplu güncelleyen JavaScript için geçerli. Tek bir uzun görev, 5 saniyelik pencere koşulunu sürekli ihlal edebilir; bölme işlemi bu koşulun sağlanmasını kolaylaştırır.

Her üç katmandaki değişikliğin etkisini ölçmek için tutarlı bir referans noktası gerekir. Sayfanın Lighthouse metriklerini analiz etmek için her müdahale sonrası bir test çalıştırmak, hangi değişikliğin TTI'ye gerçekten dokunduğunu somutlaştırır. TTI, Lighthouse puanına artık katkı sağlamasa da etkileşim gecikmesini teşhis etmek için kullanışlılığını koruyor ve raporlarda görünmeye devam ediyor.

Throttling ayarlarını sabitleyin. Lighthouse'un varsayılan 4x CPU simülasyonu, orta segment Android cihazlarını temsil eder; bu ayarda 5 saniyelik boşluk penceresi çok daha zor sağlanır. Masaüstünde sorunsuz görünen TTI değeri, bu profilde ciddi biçimde açılabilir. Özellikle e-ticaret ve SaaS uygulamalarında gerçek kullanıcı tabanının büyük bölümünü oluşturan bu cihaz kategorisi için ayrı bir Lighthouse profili tutmak, iyileştirmelerin doğru yerde aranmasını sağlar.

LCP iyileştirmesi tamamlanmış ama kullanıcı şikayeti sürüyorsa, TTI ve TBT değerlerine bakmak mantıklı bir sonraki adımdır. Sayfanın görünümü ile sayfanın davranışı her zaman aynı anda hazır olmaz; bu ikisi arasındaki mesafe, kullanıcının gerçekte ne hissettiğini belirleyen şeydir.