Uygulamayı yükle
How to install the app on iOS

Follow along with the video below to see how to install our site as a web app on your home screen.

Not: This feature may not be available in some browsers.

Event Loop İşleyişi ve Makro-Mikro Task Kuyrukları Arasındaki İnfaz Öncelikleri

batuhanunalir

Aktif üye
Yazar
Katılım
27 Tem 2025
Konular
567
Mesajlar
576
Tepkime puanı
144
Puanları
43
🌟Puan
226
💵Bakiye
0TL

Event Loop İşleyişi ve Makro-Mikro Task Kuyrukları Arasındaki İnfaz Öncelikleri​

JavaScript, web ekosisteminin can damarı olmasını "single-threaded" yani tek iş parçacıklı yapısına borçludur. Aynı anda sadece tek bir işlemi yürütebilen bu dil, tarayıcıda kullanıcı arayüzünün donmasını engellemek ve binlerce asenkron işlemi eşzamanlı gibi yönetmek zorundadır. Peki, tek bir şeride sahip olan bir yol, nasıl oluyor da devasa bir metropol trafiğini hiçbir tıkanma yaşamadan eritebiliyor? Bu mucizenin arkasında, JavaScript çalışma zamanı mimarisinin (runtime) kalbini oluşturan Event Loop (Olay Döngüsü) ve bu döngünün işleri sıraya koyduğu Makro-Mikro Task Kuyrukları yer alır. Bu yazıda, JavaScript'in asenkron yürütme motorunun derinliklerine inecek, görev kuyrukları arasındaki görünmez öncelik savaşlarını ve bu süreçlerin yazılım performansına etkilerini inceleyeceğiz.

JavaScript Motoru ve Tek İş Parçacıklı Yürütme Mimarisi​

JavaScript motorları (örneğin Google Chrome'un V8 motoru), kodları çalıştırmak için bir Call Stack (Çağrı Yığını) kullanır. Bu yığın, "son giren ilk çıkar" prensibiyle çalışır ve o an yürütülen fonksiyonları üst üste koyarak sırayla infaz eder. JavaScript tek iş parçacıklı olduğu için, Call Stack içerisinde bir işlem bitmeden altındaki işleme asla geçilemez.

Eğer çok büyük bir matematiksel hesaplama veya uzun süren bir döngü bu yığını meşgul ederse, tarayıcı sekmesi kilitlenir; kullanıcı ne bir butona tıklayabilir ne de sayfayı kaydırabilir. Bu duruma sistemin bloklanması denir. JavaScript, bu bloklanma krizini aşmak için kendi motorunun dışındaki yapılardan yardım alır: Tarayıcı API'leri (Web APIs) ve Node.js runtime ortamı. Asenkron bir işlem tetiklendiğinde, bu işlem motorun dışındaki güvenli bölgeye aktarılır ve Call Stack'in rahat nefes alması sağlanır.

Event Loop Nedir ve Nasıl Çalışır?​

Asenkron olarak arka plana gönderilen işler (örneğin bir zamanlayıcının süresinin dolması veya bir API isteğinin tamamlanması) bittiğinde, bu işlerin geri çağırım süreçlerinin yeniden Call Stack'e dönmesi gerekir. İşte Event Loop, tam bu noktada devreye giren ve hiç durmadan dönen bir trafik polisidir.

Event Loop’un tek ve çok basit bir görevi vardır: Sürekli olarak Call Stack'i ve işlerin biriktiği görev kuyruklarını denetlemek. Eğer Call Stack tamamen boşsa ve çalıştırılacak senkron bir kod kalmadıysa, Event Loop kuyrukta bekleyen ilk asenkron görevi alır ve çalıştırılması için Call Stack'e fırlatır. Bu döngü, uygulama açık olduğu sürece saniyede binlerce kez tekrarlanır. Ancak işlerin karmaşıklaştığı yer, arka plandaki tüm asenkron görevlerin aynı kuyruğa girmemesidir.

Görev Kuyruklarının Ayrımı: Makro Task ve Mikro Task​

JavaScript mimarisinde asenkron görevler, önem derecelerine ve aciliyetlerine göre iki farklı kuyruğa dağıtılır: Makro Task Kuyruğu (Task Queue) ve Mikro Task Kuyruğu (Microtask Queue). Geliştiricilerin yazdığı asenkron kodların çalışma sırasındaki beklenmedik davranışları, genellikle bu iki kuyruğun çalışma prensiplerinin karıştırılmasından kaynaklanır.

Makro Task Kuyruğu (Macro Tasks)​

Makro task'lar, tarayıcının veya runtime ortamının kendi ekosisteminden gelen, görece daha hantal ve standart asenkron işlemleri temsil eder. Event Loop her döngüde bu kuyruktan yalnızca bir adet görevi Call Stack'e taşır.

  • Kullanıcı etkileşimleri (tıklama, klavye girdileri),
  • Zamanlayıcılar (belirli bir süre sonra tetiklenecek görevler),
  • Ağ isteklerinin sonuçlanma süreçleri,
  • Sayfa render etme (çizim) döngüleri,
birer makro task örneğidir. Bu görevler, sistemin genel işleyiş akışını bozmayacak şekilde, zamana yayılarak sırayla işlenir.

Mikro Task Kuyruğu (Micro Tasks)​

Mikro task'lar ise doğrudan JavaScript kodunun kendi iç mantığından doğan, çok daha yüksek öncelikli ve acil infaz edilmesi gereken hafif görevlerdir. Yazılım dünyasında vaatleri temsil eden Promise nesnelerinin sonuçlanma süreçleri (çözümleme veya hata durumları) ve tarayıcıdaki DOM değişimlerini izleyen özel gözlemci mekanizmaları bu kuyruğa girer.

Mikro task kuyruğunun en karakteristik ve tehlikeli özelliği, Event Loop’un bu kuyruğa yaklaşım tarzıdır. Event Loop, Call Stack boşaldığı an mikro task kuyruğuna geçer ve kuyruktaki tüm görevler tamamen bitene kadar oradan ayrılmaz. Eğer bir mikro task çalışırken kendi içine yeni bir mikro task eklerse, kuyruk sonsuza kadar beslenebilir ve tarayıcının kilitlenmesine neden olabilir.

İnfaz Öncelikleri ve Kesin Çalışma Sırası​

Event Loop'un bu iki kuyruk arasındaki adalet terazisi son derece keskindir. Bir JavaScript uygulamasında kodların infaz edilme sırası matematiksel bir kesinlikle şu adımları izler:

  1. Senkron Kodların İnfazı: İlk olarak Call Stack'teki tüm senkron kodlar yukarıdan aşağıya doğru bütünüyle çalıştırılır ve yığın tamamen boşaltılır.
  2. Mikro Task Kuyruğunun Tamamen Temizlenmesi: Call Stack boşaldığı an, Event Loop doğrudan mikro task kuyruğuna bakar. Kuyrukta kaç tane Promise çözümlemesi varsa, hepsi bitene kadar sırayla çalıştırılır. Kuyruk tamamen sıfırlanmadan bir sonraki adıma geçilmez.
  3. Sayfa Render (Çizim) Aşaması: Eğer tarayıcı ekranında bir görsel güncelleme, animasyon veya stil değişikliği yapılması gerekiyorsa, mikro task'ların hemen ardından tarayıcı sayfayı yeniden çizer.
  4. Tek Bir Makro Task İnfazı: Ekran çizimi de bittikten sonra, Event Loop makro task kuyruğundan sadece en öndeki tek bir görevi (örneğin süresi dolmuş ilk zamanlayıcıyı) alır ve Call Stack'e gönderir. O tek görev bittiğinde döngü en başa döner; yani yeniden mikro task kuyruğunu kontrol eder.
Bu sıralama mantığı nedeniyle, teorik olarak bir saniye sonraya ayarlanan bir zamanlayıcı, eğer mikro task kuyruğu çok yoğunsa, asla tam zamanında çalışamaz. Çünkü mikro task'lar bitmeden makro task sırası gelemez.

Performans Darboğazları ve Bloklanma Riskleri​

Event Loop işleyişini tam olarak kavramamak, kurumsal ve yoğun veri trafiği olan projelerde ciddi performans facialarına yol açabilir. Özellikle mikro task kuyruğunun hoyratça kullanılması, kullanıcı deneyimini doğrudan baltalar.

Eğer büyük bir veri setini işlerken sürekli olarak ardışık Promise yapıları oluşturup mikro task kuyruğunu şişirirseniz, tarayıcı bir türlü üçüncü adıma, yani "Sayfa Render" aşamasına geçemez. Kullanıcı ekranda dönen bir yükleniyor animasyonu görüyorsa, bu animasyon bile donar. Çünkü tarayıcının ekranı saniyede 60 kez yenileyebilmesi için Event Loop'un düzenli olarak makro ve mikro task döngülerini tamamlayıp çizim aşamasına uğraması gerekir.

Benzer şekilde, ağır bir arka plan işini makro task yerine mikro task olarak kurgulamak, uygulamanın arayüz tepki süresini (Time to Interactive) düşürür. Yazılım mimarlarının görevi, iş yüklerini analiz ederek acil olan mantıksal süreçleri mikro task'lara, zamana yayılabilecek arayüz veya sistem süreçlerini ise makro task'lara doğru şekilde dağıtmaktır.

Geliştiriciler İçin Altın Kurallar​

JavaScript'in Event Loop mekanizması, kısıtlı kaynaklarla maksimum eşzamanlılık performansı üretmek için tasarlanmış dahi bir mühendislik harikasıdır. Ancak bu mekanizmanın kurallarını bilmeden kod yazmak, karanlıkta yürümeye benzer.

Geliştirme süreçlerinde sistem mimarisini korumak için şu kurallar rehber edinilmelidir:

  • Call Stack'i Özgür Bırakın: Ağır matematiksel operasyonları veya milyonlarca verilik döngüleri ana iş parçacığında (Main Thread) senkron olarak yürütmeyin. İş parçacığını uzun süre işgal etmek tüm uygulamayı felç eder.
  • Kuyruk Önceliklerine Saygı Duyun: Bir Promise yapısının, standart bir zamanlayıcıdan her zaman daha önce çalışacağını adınız gibi bilin. Kod sıralamasını belirlerken satır sırasına değil, görevin hangi kuyruğa girdiğine odaklanın.
  • Arayüz Akıcılığını Koruyun: Kullanıcı deneyimini etkileyen animasyon ve çizim süreçlerinin aksamaması için mikro task kuyruğunu uzun süreli işlerle boğmayın. Ağır işleri küçük parçalara bölerek makro task kuyruğuna yayın.
Event Loop ve görev kuyruklarının işleyiş mantığına hakim olmak, sizi sadece sıradan bir kod yazarı olmaktan çıkarıp, uygulamanın bellek ve yürütme performansını milisaniyeler seviyesinde optimize edebilen kıdemli bir yazılım mimarına dönüştürür.
 
Harika bir teknik anlatım olmuş, elinize sağlık! JavaScript'in asenkron doğasını anlamak, özellikle karmaşık "race condition" hatalarını çözmek ve performans darboğazlarını (bottleneck) tespit etmek için bu temel bilgiler hayati önem taşıyor.

Yazınızda belirttiğiniz "Mikro task kuyruğunun tüm elemanları bitmeden makro task'a geçilmemesi" kuralı, özellikle Promise.resolve().then() blokları içine sürekli yeni then() ekleyerek farkında olmadan tarayıcıyı kilitleyen (starvation) geliştiriciler için çok kritik bir uyarı.

Konuya ek olarak, özellikle ağır hesaplama gerektiren (CPU-intensive) işlerde Call Stack'i ve Event Loop'u tamamen özgür bırakmak isteyenler için Web Workers kullanımı da bu mimarinin bir sonraki adımı olarak düşünülebilir.

Bu derinlemesine rehber için teşekkürler, forumdaki diğer geliştiriciler için referans niteliğinde bir içerik olmuş. Başarılar dilerim!
 

Konuyu izleyenler

Günün trendleri

Geri