Chrome DevTools'un Performance paneli, bir sayfada neler olduğunu milisaniye düzeyinde görmenizi sağlar. Lighthouse puanı size "nerede sorun var" der; Performance paneli ise "bu sorunun kökü hangi fonksiyon, hangi CSS değişikliği" sorusunu yanıtlar. İkisi farklı şeyler söyler ve birinin yerine diğeri kullanılamaz.

Panel ilk açıldığında kalabalık görünür. Renkli çubuklar, iç içe katmanlar, zaman damgaları bunaltıcı gelebilir. Ama her renk ve her katmanın belirli bir anlamı vardır; bunu kavrayınca karmaşa değil harita görürsünüz.

Kayıt almadan önce şunu aklınızda tutun: profilleme işleminin kendisi de ek yük taşır. Üretim ortamını taklit eden temiz bir tarayıcı profiliyle, network ve CPU throttling açık şekilde çalışırsanız çok daha gerçekçi veriler elde edersiniz. İnkognito modda, yüklü uzantılar devre dışıyken kayıt almak iyi bir başlangıç noktasıdır.

Kayıt Almak ve Zaman Çizelgesini Okumak

Performance panelini açmak için F12'ye basın, üst sekmelerden "Performance"ı seçin. Kaydı başlatmak için dairesel Kayıt düğmesine ya da Ctrl+Shift+E kısayoluna basın. Sayfanın ilk yüklenmesini kaydetmek istiyorsanız "Start profiling and reload page" seçeneğini kullanın; bu seçenek sayfayı yenileyerek kaydı otomatik başlatır. Kayıt süresince test etmek istediğiniz etkileşimi gerçekleştirin, sonra kaydı durdurun.

Kayıt tamamlandıktan sonra zaman çizelgesi açılır. En üstte CPU aktivite grafiği yer alır; kırmızıya kayan alanlar yüksek yükü işaret eder. Altında sırasıyla network istekleri, JavaScript heap kullanımı ve sayfa ekran görüntüsü şeridi bulunur. Sarı dikey çizgiler frame sınırlarını, kırmızı üçgenler ise long task'leri işaretler; onları görür görmez dikkatinizi çekecek biçimde tasarlanmışlardır.

Zaman çizelgesini fare ile yakınlaştırabilirsiniz. İlgilendiğiniz aralığı sürükleyip seçtiğinizde, alt panelin yalnızca o zaman dilimine odaklanmasını sağlarsınız. Çok geniş görünümde küçük ayrıntılar kaybolur, çok dar görünümde bağlam yiter; performans sorunlarını izole etmek için 100-500 ms aralıkları genellikle yeterli genişlik sunar.

Flame Chart: Her Kutunun Anlamı

Flame chart (alev diyagramı), JavaScript çalışma zamanının her anında hangi fonksiyonun çalıştığını gösteren dikey yığın görünümüdür. Her kutu bir fonksiyon çağrısını temsil eder; kutunun yatay genişliği o fonksiyonun kaç milisaniye sürdüğünü gösterir. Üst sırada çağıran fonksiyon, hemen altında onun tetiklediği fonksiyon yer alır; yığın aşağıya doğru derinleşir.

Geniş kutular ilk bakılması gereken yerlerdir. 50 milisaniyenin üzerinde süren tek bir fonksiyon, kullanıcının fare tıklamalarına geç yanıt verilmesine ya da kaydırmanın takılmasına yol açabilir. Flame chart'ı okurken yatay genişliğe odaklanın; derin dikey yığınlar mutlaka sorun demek değildir, bazı yığınlar sadece derin çağrı zinciri içerir ama toplam süreleri kısadır.

Bir kutuya tıkladığınızda alt panelde o fonksiyonun adı, çalıştığı kaynak dosyası ve satır numarası çıkar. Doğrudan kaynak koduna atlamak için "Reveal in Sources" bağlantısını kullanabilirsiniz. Kayıt sırasında JavaScript dosyaları minify edilmişse, kaynak haritaları (source maps) aktifken alınan kayıtlar çok daha okunabilir veriler üretir.

Long Task Bulma ve Kırmızı Üçgenlerin Anlamı

Main thread'de 50 milisaniyenin üzerinde süren her aktivite long task sayılır. Kırmızıdır. Hemen görünür. Tarayıcının kullanıcı girdisine yanıt verebilmesi için her 50 ms'de bir fırsat bulması gerekir; bu eşik aşıldığında kullanıcı deneyimi bozulur, click veya keydown olayları geç işlenir.

Flame chart'ta long task'ler sağ üst köşesinde kırmızı üçgen bulunan geniş sarı bloklar olarak belirir. Zaman çizelgesinin üst şeridinde de aynı işaretleyicileri görebilirsiniz. Bir long task üzerine tıkladığınızda alt panelde "Long Task" etiketi ve tam süresi çıkar; flame chart katmanlarını inceleyerek hangi alt çağrıların en fazla zaman tükettiğini saptayabilirsiniz.

Sorun her zaman tek bir fonksiyon değildir. Long task'in içinde birden fazla küçük fonksiyon art arda çalışıyor olabilir ve toplamları 50 ms'yi geçiyor olabilir; bu durum flame chart'ta yan yana dizilmiş dar kutular dizisi olarak kendini gösterir. Hangi alt çağrıların birleşerek uzun bir task oluşturduğunu görmek için yığın katmanlarını aşağıdan yukarıya izleyin.

Long task'i bulduktan sonra yapılacak şey, o task'in kırılabilir olup olmadığını değerlendirmektir. İş parçalara bölünebiliyorsa setTimeout(..., 0) veya modern scheduler.postTask() API'siyle yayabilirsiniz; bölünemiyorsa ve yalnızca hesaplama yapıyorsa Web Worker'a taşımak daha doğru bir tercih olur. Her long task bu iki seçenekten birine uygun olmayabilir; bazı işlemler DOM erişimi gerektirdiği için main thread dışına çıkarılamaz.

Main Thread Aktivitelerini Renk Kodlarıyla Gruplama

DevTools her aktiviteyi renk kodlayarak gruplar. Sarı JavaScript çalıştırmayı (scripting), mor layout ve Recalculate Style gibi render hesaplamalarını, yeşil paint ve composite işlemlerini, mavi ise HTML parse ile network kaynaklı aktiviteleri temsil eder. Gri kalan alanlar tarayıcının kendi işleyişine aittir.

Bir performans sorununda önce hangi rengin baskın olduğunu belirleyin. Sarı ağır basıyorsa JavaScript kodunun kendisi yavaş ya da çok sık tetikleniyor; mor ağır basıyorsa DOM büyüklüğü ya da CSS seçici karmaşıklığı artmış; yeşil ağır basıyorsa paint bölgeleri gereğinden fazla genişlemiş demektir. Renk dağılımı size hangi optimizasyon yoluna gireceğinizi söyler.

Yalnızca rengi değil pattern'i de okuyun. Sürekli aralıksız sarı değil, kesik kesik morlar görüyorsanız, JavaScript'in tetiklediği layout hesaplamalarının (forced synchronous layout) döngüye girmiş olma ihtimali yüksektir; flame chart'ta bu durum, sarı kutunun içinden çıkan art arda mor bloklarla tanınır. Sarının ardından gelen mor, ardından sarı, ardından tekrar mor şeklinde bir ritim kötü bir işaret sayılır ve genellikle okuma-yazma döngüsünün sıkıştırılmamış olduğunu gösterir.

Layout ve Paint Maliyetini İzole Etmek

Layout (yeniden yerleşim hesabı) tüm sayfayı ya da sayfanın bir bölümünü etkiler; bir elementin boyutu değiştiğinde çevresi de hesaplanmak zorundadır. Paint ise piksel çizme işlemidir ve etkilenen bölgeye sınırlıdır. İkisi de pahalıdır, ama birbirinden farklı nedenlerle.

JavaScript ile DOM değişikliği yapıp hemen ardından getBoundingClientRect() veya offsetWidth gibi bir ölçüm okuyorsanız tarayıcı, okuma gerçekleşmeden önce layout'ı tamamlamak zorunda kalır. Buna forced synchronous layout denir ve flame chart'ta JS kutusu bitmeden başlayan mor blok olarak görünür. Çözüm basittir: önce tüm DOM okumalarını yapın, sonra tüm yazmaları gerçekleştirin; böylece tarayıcı layout'ı tek seferde hesaplar.

Paint maliyetini izole etmek için Rendering sekmesinde "Paint flashing" seçeneğini açın. Boyanan bölgeler yeşil dikdörtgenlerle vurgulanır. Beklediğinizden geniş bir alan sürekli boyandığında, CSS will-change: transform kullanarak o elementi ayrı bir compositor katmanına taşıyabilirsiniz. Ama dikkatli olun: her element için bunu yapmak GPU belleğini artırır ve ters etki yaratabilir. Gerçekten sık boyanan, diğer elementlerden bağımsız hareket eden öğeler için anlamlıdır; statik içerik için gereksizdir.

Composite-only özellikler olan transform ve opacity, GPU'nun üstlendiği işlemlerdir. Layout veya paint tetiklemeden çalıştıkları için animasyon maliyeti en düşük seçeneklerdir. Bir elementin konumunu değiştirmek için left/top yerine transform: translate() kullanmak, flame chart'taki mor ve yeşil bloğu ortadan kaldırır; yalnızca bir composite işlemi kalır.

Bottom-Up ve Call Tree ile Fonksiyon Bulmak

Flame chart görsel okuma için güçlüdür, ama hangi fonksiyonun toplam zamana en çok katkıda bulunduğunu bulmak için alt sekmeler daha pratiktir.

"Bottom-Up" sekmesi, en çok self time (alt çağrılar hariç, yalnızca kendi içinde harcanan süre) kullanan fonksiyonu üstte listeler. Bir döngü içinde defalarca çağrılan küçük bir fonksiyon burada belirginleşir; flame chart'ta birçok dar kutu olarak dağıldığı için gözden kaçabilirken Bottom-Up onu bir arada gösterir. Kaynak dosyası ve satır numarasıyla birlikte listelenir, tıklayınca flame chart'ta konumuna atlanır.

"Call Tree" ise başlangıç noktasından aşağı doğru iner; hangi çağrı zinciri toplam maliyeti oluşturduğunu gösterir. Ağaç görünümü sayesinde bir event handler'ın tetiklediği tüm alt çağrıları ve her birinin ağırlığını görebilirsiniz. "Event Log" sekmesi zaman damgasıyla tüm olayları sıralar; tıklama ile ilk frame arasındaki zinciri adım adım izlemek istiyorsanız burası daha uygundur.

Hangi sekmeye bakacağınız soruya göre değişir. Belirli bir fonksiyonun toplam maliyetini arıyorsanız Bottom-Up, gelen bir kullanıcı etkileşiminin nasıl işlendiğini anlamak istiyorsanız Call Tree, belirli bir etkileşimin kronolojisini takip ediyorsanız Event Log doğru seçimdir. Üç sekmeyi birlikte kullanmak, tek başına flame chart okumaktan genellikle daha hızlı sonuç verir.

Performance paneli büyük miktarda veri üretir; her şeyi aynı anda çözmeye çalışmak yerine tek bir soruyla başlamak daha verimlidir. Long task var mı? Varsa hangi fonksiyon? O fonksiyon kırılabilir mi ya da taşınabilir mi? Bu zincir sizi somut adımlara götürür ve olası yolların sayısını hızla azaltır.

Kayıt almak, zaman çizelgesini okumak ve değişikliğin ardından ölçümü tekrarlamak bir alışkanlık hâline gelince yavaş sayfanın neden yavaş olduğunu tahmin etmek yerine görmek mümkün olur. Tarayıcı zaten her şeyi milisaniye düzeyinde kaydediyor; paneli okumak bu veriyi anlama dönüştürmek demektir.