Merhaba arkadaşlar, bugün başımı çok ağrıtan bir sorunu ve nasıl çözdüğümü anlatacağım. Kullanıcılar, "Sayfa bazen donuyor gibi oluyor" diye feedback vermeye başlamıştı. İlk başta "Bizim local'de çok hızlı çalışıyor" deyip geçiştirdim ama sonra ciddi bir performans bottleneck'i olduğunu fark ettim. İşte tam bu noktada, Chrome DevTools'un
Performance Tab'ı imdadıma yetişti.
Performance Kaydı Nasıl Alınır?
Öncelikle, sorunu gözle görmek için bir kayıt almak şart. Chrome DevTools'u açtıktan sonra (F12), Performance sekmesine geçiyorsunuz. Sayfada, sorunu tetikleyecek bir işlem yapmadan hemen önce (örneğin bir butona tıklayacaksanız) kaydı başlatın (Record butonu veya Ctrl+E). İşlemi yapın ve ardından kaydı durdurun. Karşınıza detaylı bir zaman çizelgesi çıkacak.
Timeline'ı Okumak ve Long Tasks'ı Bulmak
Bu timeline'da en çok dikkat etmeniz gereken şey, 50 milisaniyeyi (ms) aşan uzun, kırmızımsı çubuklar. Bunlar "Long Tasks" yani uzun görevlerdir. Tarayıcının ana thread'ini (UI thread) bu süre boyunca meşgul ederler ve bu da sayfanın donmasına, tıklamalara geç cevap vermesine neden olur. Benim sorunum da tam olarak buydu: bir veri listesini filtrelerken 300ms'yi aşan devasa bir sarı (Scripting) çubuk görüyordum.
Sorunun Kök Sebebini İncelemek
O uzun görevin üzerine tıkladığınızda, altta Bottom-Up veya Call Tree sekmesi açılır. Burada hangi fonksiyonun ne kadar süre harcadığını görebilirsiniz. Benim durumumda, suçlu çok açıktı: renderItemList isimli bir fonksiyon, içinde yapılan ağır bir sıralama (sort) işlemi ve her bir liste öğesi için gereksiz yere çağrılan kompleks bir formatlama fonksiyonuydu.
İşte o kritik kodu ilk haliyle görmek için:
Çözüm ve Optimizasyon Stratejim
Burada iki büyük hata vardı:
1. Sıralama (sort), orijinal diziyi değiştiriyor ve her render'da tekrar çalışıyordu. Üstelik veri değişmemiş olsa bile.
2. Formatlama fonksiyonları, her bir öğe için her seferinde yeniden hesaplanıyordu.
Çözüm olarak şunları uyguladım:
1. Memoization (useMemo / Belleğe Alma): Sıralanmış listeyi ve formatlanmış verileri, bağımlı oldukları `items` dizisi değişmediği sürece yeniden hesaplamaktan kaçındım.
2. Web Worker (Opsiyonel, çok ağırsa): Eğer sıralama gerçekten çok karmaşık olsaydı, bu işi ana thread'den ayırmak için Web Worker düşünebilirdim. Benim durumumda memoization yeterli oldu.
3. Tembel Yükleme (Lazy Initialization): Formatlama fonksiyonlarını, sadece ihtiyaç duyulduğunda çağırılacak şekilde revize ettim.
İşte optimizasyon sonrası kod:
Bu değişiklikten sonra Performance tab'ında yeniden kayıt aldığımda, o kocaman kırmızı çubuk kaybolmuş ve yerine birkaç küçük, yeşil çubuk (kısa görevler) gelmişti. Sayfa akıcılığı inanılmaz derecede arttı.
Sonuç ve Düşünceler
Chrome DevTools Performance tab'ı, frontend optimizasyonunun olmazsa olmazı. Gözle görülmeyen ancak kullanıcı deneyimini doğrudan etkileyen Long Tasks'ları tespit etmek için mükemmel bir araç. Bazen kodunuz "çalışıyor" olabilir, ancak "iyi çalışıyor" mu?
Siz de projelerinizde benzer donma problemleri yaşadınız mı? Performans bottleneck'lerini tespit etmek için Performance tab'ı dışında farklı araçlar veya yöntemler kullanıyor musunuz? Özellikle büyük veri setleriyle çalışırken kullandığınız başka taktikler varsa yorumlarda paylaşın, hep birlikte öğrenelim!
Öncelikle, sorunu gözle görmek için bir kayıt almak şart. Chrome DevTools'u açtıktan sonra (F12), Performance sekmesine geçiyorsunuz. Sayfada, sorunu tetikleyecek bir işlem yapmadan hemen önce (örneğin bir butona tıklayacaksanız) kaydı başlatın (Record butonu veya Ctrl+E). İşlemi yapın ve ardından kaydı durdurun. Karşınıza detaylı bir zaman çizelgesi çıkacak.
Bu timeline'da en çok dikkat etmeniz gereken şey, 50 milisaniyeyi (ms) aşan uzun, kırmızımsı çubuklar. Bunlar "Long Tasks" yani uzun görevlerdir. Tarayıcının ana thread'ini (UI thread) bu süre boyunca meşgul ederler ve bu da sayfanın donmasına, tıklamalara geç cevap vermesine neden olur. Benim sorunum da tam olarak buydu: bir veri listesini filtrelerken 300ms'yi aşan devasa bir sarı (Scripting) çubuk görüyordum.
O uzun görevin üzerine tıkladığınızda, altta Bottom-Up veya Call Tree sekmesi açılır. Burada hangi fonksiyonun ne kadar süre harcadığını görebilirsiniz. Benim durumumda, suçlu çok açıktı: renderItemList isimli bir fonksiyon, içinde yapılan ağır bir sıralama (sort) işlemi ve her bir liste öğesi için gereksiz yere çağrılan kompleks bir formatlama fonksiyonuydu.
İşte o kritik kodu ilk haliyle görmek için:
JavaScript:
// PROBLEMLİ KOD (Long Task'a sebep olan)
function renderItemList(items) {
// 1. Ağır sıralama işlemi
const sortedItems = items.sort((a, b) => {
// Çok karmaşık bir karşılaştırma mantığı
return new Date(b.createdAt) - new Date(a.createdAt) || a.name.localeCompare(b.name);
});
// 2. Her öğe için ağır formatlama
return sortedItems.map(item => {
const formattedDate = complexDateFormatter(item.createdAt); // Uzun süren fonksiyon
const processedName = expensiveStringProcessor(item.name); // Başka bir uzun fonksiyon
return `<div>${processedName} - ${formattedDate}</div>`;
});
}
Burada iki büyük hata vardı:
1. Sıralama (sort), orijinal diziyi değiştiriyor ve her render'da tekrar çalışıyordu. Üstelik veri değişmemiş olsa bile.
2. Formatlama fonksiyonları, her bir öğe için her seferinde yeniden hesaplanıyordu.
Çözüm olarak şunları uyguladım:
1. Memoization (useMemo / Belleğe Alma): Sıralanmış listeyi ve formatlanmış verileri, bağımlı oldukları `items` dizisi değişmediği sürece yeniden hesaplamaktan kaçındım.
2. Web Worker (Opsiyonel, çok ağırsa): Eğer sıralama gerçekten çok karmaşık olsaydı, bu işi ana thread'den ayırmak için Web Worker düşünebilirdim. Benim durumumda memoization yeterli oldu.
3. Tembel Yükleme (Lazy Initialization): Formatlama fonksiyonlarını, sadece ihtiyaç duyulduğunda çağırılacak şekilde revize ettim.
İşte optimizasyon sonrası kod:
JavaScript:
// OPTİMİZE EDİLMİŞ KOD (useMemo örneği - React)
import React, { useMemo } from 'react';
function ItemList({ items }) {
// Bağımlılık (items) değişmediği sürece, ağır işlem TEKRAR ÇALIŞMAZ.
const sortedAndFormattedItems = useMemo(() => {
console.log('Ağır hesaplama çalıştı!');
// 1. Sıralama: Yeni bir dizi oluşturup onu sırala (orijinali değiştirme)
const sorted = [...items].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt) || a.name.localeCompare(b.name));
// 2. Formatlama: Sıralanmış diziyi map'le geçip formatla
return sorted.map(item => ({
...item,
// Formatlama işlemleri artık daha hafif ve kontrollü
displayText: `${item.name} - ${new Date(item.createdAt).toLocaleDateString('tr-TR')}`
}));
}, [items]); // Sadece `items` değiştiğinde yeniden hesapla
return (
<div>
{sortedAndFormattedItems.map(item => (
<div key={item.id}>{item.displayText}</div>
))}
</div>
);
}
Bu değişiklikten sonra Performance tab'ında yeniden kayıt aldığımda, o kocaman kırmızı çubuk kaybolmuş ve yerine birkaç küçük, yeşil çubuk (kısa görevler) gelmişti. Sayfa akıcılığı inanılmaz derecede arttı.
Chrome DevTools Performance tab'ı, frontend optimizasyonunun olmazsa olmazı. Gözle görülmeyen ancak kullanıcı deneyimini doğrudan etkileyen Long Tasks'ları tespit etmek için mükemmel bir araç. Bazen kodunuz "çalışıyor" olabilir, ancak "iyi çalışıyor" mu?
Siz de projelerinizde benzer donma problemleri yaşadınız mı? Performans bottleneck'lerini tespit etmek için Performance tab'ı dışında farklı araçlar veya yöntemler kullanıyor musunuz? Özellikle büyük veri setleriyle çalışırken kullandığınız başka taktikler varsa yorumlarda paylaşın, hep birlikte öğrenelim!