Lighthouse raporunuzda LCP ve CLS yeşil görünüyor ama performans skoru bir türlü 70'in üzerine çıkmıyorsa, suçlu neredeyse kesinlikle TBT'dir. TBT (Total Blocking Time), yani toplam engelleme süresi, sayfa yüklenirken tarayıcının ana iş parçacığının ne kadar süre boyunca kullanıcı girdisine cevap veremeyecek kadar meşgul kaldığını ölçer. Sayfa gözünüzle bakınca hazırdır, ama tıkladığınızda hiçbir şey olmaz; işte o ölü aralığın toplamı TBT'dir.
Bu rehberde TBT'nin nasıl hesaplandığını, neden Lighthouse skorunun en ağır kalemi olduğunu, uzun görevleri nasıl bulup böleceğinizi ve üçüncü taraf betiklerinin bu tabloyu nasıl mahvettiğini anlatacağım. TBT bir laboratuvar metriğidir; gerçek kullanıcı tarafındaki karşılığı INP'dir. İkisi arasındaki ilişkiyi kurduğunuzda hangi düzeltmenin gerçek dünyada karşılık bulacağını da öngörebilirsiniz.
TBT Tam Olarak Neyi Ölçer#
TBT'yi anlamak için önce "uzun görev" (long task) kavramını oturtmak gerekir. Tarayıcının ana iş parçacığı tek şeritli bir yoldur: JavaScript çalıştırma, stil hesaplama, düzen (layout) ve boyama hepsi sırayla bu şeritte yapılır. Bir JavaScript görevi 50 milisaniyeden uzun sürerse, o süre boyunca tarayıcı başka hiçbir şeyle ilgilenemez; kullanıcı tıklasa da o tık kuyrukta bekler. 50 ms'yi aşan her göreve uzun görev denir.
TBT, FCP ile TTI (Time to Interactive) arasındaki pencerede gerçekleşen uzun görevlerin 50 ms'yi aşan kısımlarının toplamıdır. Kritik nokta şu: görevin tamamı değil, sadece 50 ms'nin üzerindeki payı sayılır. Bir örnek üzerinden bakalım:
| Görev | Süre | Engelleme payı |
|---|---|---|
| Uygulama paketini ayrıştırma | 320 ms | 270 ms |
| Analiz betiği başlatma | 90 ms | 40 ms |
| Sohbet widget'ı kurulumu | 210 ms | 160 ms |
| Küçük olay bağlama | 30 ms | 0 ms |
| Toplam TBT | 470 ms |
Görüldüğü gibi 30 ms'lik görev hiç sayılmaz, çünkü tarayıcı iki görev arasında nefes alıp bekleyen tıklamayı işleyebilir. 320 ms'lik görev ise tek başına neredeyse üç kullanıcı etkileşimini kaçırmaya yeter. Bu yüzden TBT'yi düşürmenin yolu görev sayısını azaltmaktan çok, uzun görevleri küçük parçalara bölmektir.
TBT, FID ve INP Arasındaki İlişki#
TBT bir laboratuvar metriğidir: sabit bir cihazda, sabit bir ağda, sayfa yüklenirken ölçülür. Gerçek kullanıcı verisinde TBT diye bir alan yoktur. Onun yerine önce FID (First Input Delay), 2024'ten itibaren ise INP (Interaction to Next Paint) kullanılır.
Aradaki fark önemlidir. TBT sayfa yüklenirken oluşan engellemeyi ölçer; INP ise sayfanın tüm ömrü boyunca yaşanan etkileşim gecikmelerinin en kötüsüne yakın bir değeri raporlar. Yani TBT yükleme anına, INP kullanım anına bakar. Buna rağmen aralarında güçlü bir korelasyon vardır: ağır bir JavaScript paketi hem yükleme sırasında hem de kullanım sırasında ana iş parçacığını tıkar.
Pratik kural şudur: TBT'yi düşüren müdahalelerin çoğu INP'yi de düşürür, ama tersi her zaman doğru değildir. Örneğin bir olay dinleyicisindeki ağır hesaplamayı optimize etmek INP'yi iyileştirir ama TBT'ye dokunmaz, çünkü o kod yükleme sırasında çalışmaz. INP tarafındaki müdahalelerin ayrıntısını INP nedir ve nasıl iyileştirilir yazısında ele aldım; metriklerin genel haritası için Core Web Vitals rehberine bakabilirsiniz.
Eşik Değerler ve Lighthouse Skorundaki Ağırlığı#
TBT için kabul edilen eşikler ve Lighthouse performans skorundaki ağırlık şöyledir:
| Değerlendirme | TBT (mobil) | Anlamı |
|---|---|---|
| İyi | 200 ms ve altı | Etkileşim akıcı |
| İyileştirme gerekli | 200 – 600 ms | Tıklamalarda takılma hissi |
| Zayıf | 600 ms üzeri | Sayfa donmuş gibi algılanır |
TBT, Lighthouse performans skorunun yaklaşık yüzde otuzunu oluşturur; tek bir metrik için bu çok yüksek bir paydır. Bu yüzden skorunuzu yükseltmenin en hızlı yolu genellikle TBT'yi düşürmektir. Skorun nasıl hesaplandığını ve hangi denetimin hangi ağırlığa sahip olduğunu Lighthouse raporu nasıl okunur yazısında ayrıntılı açıkladım.
Bir uyarı: masaüstü profilinde TBT neredeyse her zaman düşük çıkar, çünkü masaüstü işlemcisi aynı JavaScript'i dört beş kat hızlı çalıştırır. Gerçek durumu görmek için mutlaka mobil profil ve işlemci kısıtlaması (CPU throttling) ile ölçüm yapın.
Uzun Görevleri Bulmak#
Uzun görevleri iki yoldan görebilirsiniz. Birincisi Chrome DevTools'un Performance panelidir: kayıt alıp zaman çizelgesindeki kırmızı köşeli sarı bloklara bakarsınız; her biri bir uzun görevdir ve üzerine tıkladığınızda hangi fonksiyonun ne kadar sürdüğünü gösteren bir alev grafiği (flame chart) açılır. Panelin kullanımını Chrome DevTools performans paneli yazısında adım adım anlattım.
İkinci yol, uzun görevleri kod ile yakalamaktır. Bu yöntem üretimde gerçek kullanıcılardan veri toplamak için de kullanılabilir:
// 50 ms'yi asan her gorevi konsola yaz
new PerformanceObserver((list) => {
for (const task of list.getEntries()) {
console.log(
"Uzun gorev:", Math.round(task.duration) + "ms",
"| kaynak:", task.attribution?.[0]?.name ?? "bilinmiyor"
);
}
}).observe({ type: "longtask", buffered: true });
Bu gözlemciyi sayfanın en başına koyup sayfayı yenilediğinizde, konsolda hangi görevin ne kadar sürdüğünü sırayla görürsünüz. attribution alanı her zaman kesin bilgi vermez ama çoğu durumda suçlu betiğin hangi çerçeveden geldiğini işaret eder.
Toplam TBT'yi komut satırından ölçmek için Lighthouse yeterlidir:
# Mobil profilde TBT olcumu
npx lighthouse https://firmaniz.com/ \
--only-audits=total-blocking-time \
--form-factor=mobile --throttling-method=simulate \
--output=json --output-path=./tbt.json --quiet
node -e "const r=require('./tbt.json');console.log('TBT:', r.audits['total-blocking-time'].displayValue)"
JavaScript Paketini Küçültmek#
TBT'nin kökü neredeyse her zaman ayrıştırılan ve çalıştırılan JavaScript miktarıdır. Tarayıcı 1 MB'lık bir paketi indirmekle kalmaz; onu ayrıştırır, derler ve çalıştırır. Orta seviye bir Android telefonda bu üçlü, indirme süresinden çok daha uzun sürer.
İlk adım, gerçekten ne kadarının kullanıldığını ölçmektir. DevTools'ta Coverage sekmesi (Ctrl+Shift+P → "Show Coverage") her dosyanın yüzde kaçının çalıştığını gösterir. Yüzde 60 kullanılmamış bir paket görmek çok yaygındır. Çözüm sırasıyla şu üç tekniktir:
- Kod bölme (code splitting). Sayfa başına yalnızca o sayfanın ihtiyacı olan kodu gönderin. Modern derleyicilerde dinamik
import()bunu otomatik yapar. - Tembel yükleme. Görünür alanın altındaki bileşenleri (grafik kütüphanesi, harita, video oynatıcı) kullanıcı oraya gelene kadar yüklemeyin.
- Ağır bağımlılıkları değiştirmek. Tek bir tarih biçimlendirme fonksiyonu için 70 KB'lık bir kütüphane taşımanın anlamı yoktur.
Dinamik yükleme pratikte şöyle görünür:
// Grafik kutuphanesi sadece kullanici sekmeye tikladiginda yuklensin
document.querySelector("#rapor-sekme").addEventListener("click", async () => {
const { Grafik } = await import("./grafik.js");
new Grafik(document.querySelector("#kutu")).ciz();
}, { once: true });
Bu tek değişiklik, ilk yüklemede ayrıştırılan kod miktarını ciddi biçimde azaltır ve TBT'ye doğrudan yansır.
Üçüncü Taraf Betikleri: En Büyük Tek Kalem#
Kendi kodunuzu ne kadar optimize ederseniz edin, sayfaya eklenen her harici etiket ana iş parçacığında sizin kontrol edemediğiniz bir görev yaratır. Tipik bir kurumsal sitede TBT'nin yarısından fazlası şu dörtlüden gelir: etiket yöneticisi, sohbet widget'ı, ısı haritası aracı ve reklam ağı.
Bunları yönetmenin üç pratik yolu var. Birincisi, hepsini async ile yüklemek ve mümkünse load olayından sonraya ertelemektir. İkincisi, sohbet ve ısı haritası gibi araçları kullanıcı etkileşime geçene kadar hiç yüklememektir:
// Sohbet widget'ini ilk etkilesime kadar erteleyen basit desen
let yuklendi = false;
const yukle = () => {
if (yuklendi) return;
yuklendi = true;
const s = document.createElement("script");
s.src = "https://ornek-sohbet.com/widget.js";
s.async = true;
document.body.appendChild(s);
};
["pointerdown", "keydown", "touchstart", "scroll"].forEach((olay) =>
window.addEventListener(olay, yukle, { once: true, passive: true })
);
setTimeout(yukle, 6000); // hic etkilesim olmazsa yine de yukle
Üçüncü yol ise en zoru ama en etkilisi: her ay etiketleri gözden geçirip artık kullanılmayanları silmek. Uygulamada pazarlama ekiplerinin eklediği etiketlerin önemli bir bölümü aylar önce anlamını yitirmiş olur ve kimse kaldırmayı düşünmez.
Ana İş Parçacığını Boşaltmak#
Bazı işler kaçınılmaz olarak ağırdır: büyük bir listeyi sıralamak, veriyi dönüştürmek, arama indeksi kurmak. Bunları silemezsiniz ama ana iş parçacığından çıkarabilir ya da parçalara bölebilirsiniz. En basit teknik, döngünün arasında tarayıcıya nefes aldırmaktır:
// Uzun donguyu parcalara bol, arada tarayiciya sira ver
async function parcaliIsle(kayitlar, isle) {
const basla = performance.now();
for (let i = 0; i < kayitlar.length; i++) {
isle(kayitlar[i]);
// Her 40 ms'de bir kontrolu tarayiciya birak
if (performance.now() - basla > 40) {
await new Promise((r) => setTimeout(r, 0));
}
}
}
Gerçekten ağır hesaplamalar içinse doğru araç Web Worker'dır: kod ayrı bir iş parçacığında çalışır ve ana iş parçacığını hiç meşgul etmez. Worker'a taşımanın maliyeti, veriyi ileri geri kopyalamaktır; küçük işler için bu maliyet kazançtan fazla olabilir, o yüzden ölçmeden taşımayın.
Sık Yapılan Hatalar#
En sık gördüğüm hata, TBT'yi masaüstünde ölçüp sorun yok sanmaktır. Masaüstü Lighthouse profilinde 80 ms çıkan bir değer, orta sınıf bir telefonda rahatlıkla 700 ms olur. Ölçümü her zaman mobil profil ve 4x CPU kısıtlamasıyla yapın.
İkinci hata, dosyayı küçültmekle çalıştırma süresini karıştırmaktır. Minify ve gzip indirme süresini kısaltır, ancak ayrıştırma ve çalıştırma süresini pek değiştirmez; çünkü tarayıcı yine aynı miktarda kodu işler. TBT'yi düşüren şey gönderilen kod miktarının azalmasıdır, sıkıştırılmış boyutun değil.
Üçüncü hata, her şeyi defer yapıp sorunun çözüldüğünü sanmaktır. defer, betiğin HTML ayrıştırmasını engellemesini önler ama betik yine de çalışır ve yine uzun bir görev yaratır; sadece daha geç yapar. TBT penceresi FCP'den sonra başladığı için ertelenmiş betik çoğu zaman tam da o pencerenin içine düşer.
Dördüncü hata, önbellek eklentisinin TBT'yi düzelteceğini ummaktır. Önbellek sunucu tarafını hızlandırır, FCP'yi iyileştirir, ama tarayıcıya gönderilen JavaScript aynı kalır. TBT tamamen istemci tarafı bir sorundur.
Sıkça Sorulan Sorular#
TBT kaç ms olmalı#
Mobil profilde 200 ms ve altı iyi kabul edilir, 200-600 ms arası iyileştirme gerektirir, 600 ms üzeri zayıftır. Statik bir tanıtım sayfasında 50 ms'nin altına inmek zor değildir. Ağır bir tek sayfa uygulamasında 200 ms hedefine ulaşmak ciddi bir kod bölme çalışması gerektirir ama ulaşılabilir bir hedeftir.
TBT gerçek kullanıcı verisinde neden görünmüyor#
Çünkü TBT bir laboratuvar metriğidir ve tanımı gereği sayfa yükleme penceresine bağlıdır. Gerçek kullanıcılarda ne zaman ölçümün biteceğini belirleyen sabit bir TTI anı yoktur. Bu yüzden saha verisinde onun yerine INP kullanılır. TBT'yi, INP'nin yükleme anındaki tahmini olarak düşünebilirsiniz.
TBT'yi düşürmek için hangi düzeltmeden başlamalıyım#
Önce en uzun tek görevi bulun ve onunla ilgilenin; 400 ms'lik tek bir görev, 50 ms'lik on görevden daha zararlıdır. Genellikle bu görev ya ana uygulama paketinin ayrıştırılması ya da bir üçüncü taraf widget'ının kurulumu olur. Üçüncü taraf betiklerini ertelemek çoğu sitede en hızlı ve en düşük riskli kazançtır.
Etiket yöneticisi TBT'yi ne kadar etkiler#
Etiket yöneticisinin kendisi küçüktür ama içinden yüklediği etiketler ana iş parçacığında birikir; ölçtüğüm sitelerde tek başına 150-400 ms arası TBT eklediği çok oldu. En sağlıklı yaklaşım, etiket yöneticisini load olayından sonra yüklemek ve içindeki etiketleri düzenli olarak temizlemektir.
Web Worker kullanmak zorunda mıyım#
Hayır, çoğu site için gerekli değildir. Worker, gerçekten ağır ve saf hesaplama içeren işler için mantıklıdır: büyük veri dönüştürme, istemci tarafı arama indeksi, görüntü işleme gibi. Sıradan bir kurumsal sitede kod bölme, tembel yükleme ve üçüncü taraf ertelemesi TBT'yi zaten hedefe indirir.
TBT ile TTI arasındaki fark nedir#
TTI, sayfanın güvenilir biçimde etkileşime hazır hâle geldiği anı verir; TBT ise o ana kadar biriken engelleme miktarını verir. TTI tek bir kötü görev yüzünden kolayca sıçrayabildiği için kararsız bir metriktir ve Lighthouse skorundaki ağırlığı zamanla azaltılmıştır. TBT daha istikrarlı ve yol gösterici bir ölçüdür.
Kapanış#
TBT, sitenizin "görünürde hazır ama aslında donmuş" olduğu süreyi ölçer ve Lighthouse skorunuzun en ağır kalemidir. Aklınızda kalması gereken dört alışkanlık: ölçümü mutlaka mobil profil ve işlemci kısıtlamasıyla yapın, en uzun tek görevi bulup onunla başlayın, üçüncü taraf betiklerini ilk etkileşime kadar erteleyin ve gönderdiğiniz JavaScript miktarını sıkıştırılmış boyutla değil ayrıştırılan kod miktarıyla değerlendirin.
JavaScript tarafını toparladıktan sonra sunucu kaynaklı gecikmeler kalırsa, ayrılmış işlemci gücü gerçekten fark yaratır: VDS ve bulut sunucu paketlerimiz derleme ve önbellek süreçleri için rahat bir alan sağlar. Sitenizin performans denetimini ve düzeltmelerini bize bırakmak isterseniz sunucu yönetimi hizmetimiz bu döngüyü üstlenir; arama performansını da birlikte ele almak isterseniz SEO tarafındaki çalışmalarımıza göz atabilirsiniz.