Geri

Nedir bu Call Stack ve Event Loop?

Doğukan BatalGüncellendi

Bu yazıda
  1. Call stack
  2. Asenkron işlem
  3. Kaynaklar

JavaScript’le uğraşan herkes call stack ve event loop’la er geç karşılaşıyor, çoğu zaman da asenkron bir işin neden yanlış sırada çalıştığını ararken. Bu yazıda ikisini iki küçük örnekle anlatıyorum.

Call stack

JavaScript tek iş parçacığında (single-thread) çalışır. Tek bir call stack’i vardır, o yüzden aynı anda tek bir iş yapar. Chrome’daki V8 gibi motorlar, o an neyin çalıştığını bu stack üzerinden takip eder. Stack son giren ilk çıkar (LIFO) mantığıyla işler: en son eklenen fonksiyon ilk biter.

Stack’in etrafında birkaç parça daha var:

  • Memory heap. Oluşturduğumuz değişkenlerin, objelerin ve fonksiyonların tutulduğu yer.
  • Web API’ler. JavaScript tek iş parçacıklı ama tarayıcı değil. Bir API isteği ya da zamanlayıcı gibi asenkron bir iş başlattığında tarayıcı bunu stack’in dışında yürütür, stack de yoluna devam eder. Diyelim ki setTimeout ile bir saniye sonra konsola “hello” yazdırmak istiyorsun. Önce setTimeout() stack’e girer, callback’i bir saniyelik bekleme süresiyle Web API’lere bırakır ve stack’ten çıkar. Hiçbir şey bloklanmaz. Bir saniye dolunca callback, callback queue’ya geçer; stack boşaldığında event loop onu stack’e alır.
  • Callback queue. Web API’lerdeki asenkron iş bitince callback burada sırasını bekler.
  • Event loop. Call stack boşalır boşalmaz kuyruktaki ilk callback’i alıp stack’e koyar.

Memory Heap ve Call Stack ile Web API’ler (DOM, setTimeout, AJAX, setInterval), Callback Queue ve Event Loop arasındaki akışı gösteren diyagram

Aşağıdaki kodda üç fonksiyon var. foo konsola “foo”, bar da “bar” yazıyor. hello önce foo ile bar’ı çağırıyor, sonra konsola “hello” yazıyor. Son satırda da hello() çağrılıyor.

function foo(){
  console.log("foo");
}

function bar(){
  console.log("bar");
}

function hello(){
  foo();
  bar();
  console.log ("hello");
}

hello();

hello() fonksiyonunun foo() ve bar() çağrılarıyla call stack’e eklenip çıkarılmasını gösteren animasyon

Kod yukarıdan aşağı çalışıyor:

  • hello() stack’e giriyor. İçinde foo() çağrıldığı için foo da onun üstüne ekleniyor. foo bir console.log çağırıyor, o da en üste geliyor. Stack LIFO çalıştığı için önce console.log çalışıp çıkıyor, ardından işi biten foo da çıkıyor.
  • hello hâlâ stack’te, çünkü işi bitmedi. Şimdi bar ekleniyor, aynı şekilde “bar” yazıp çıkıyor.
  • Son olarak hello konsola “hello” yazıyor. Bu console.log da girip çalışıyor ve çıkıyor. Yapacak başka işi kalmayan hello da stack’ten ayrılıyor.

Asenkron işlem

Aynı fikri bir de setTimeout ile görelim:

console.log("hello");

function world(){
     console.log("world")
}

setTimeout(function cbFunction(){
     console.log("Callback Function")
}, 1000);

world();

setTimeout callback’inin Web API’lerden callback queue’ya, oradan call stack’e geçişini gösteren animasyon

  • İlk satır stack’e giriyor, konsola “hello” yazıp çıkıyor.
  • world, konsola “world” yazan bir fonksiyon. setTimeout’tan sonra çağrılıyor.
  • setTimeout stack’e giriyor, cbFunction’ı 1000 ms’lik bekleme süresiyle Web API’lere bırakıyor ve stack’ten çıkıyor.
  • world() ve içindeki console.log sırayla stack’e girip çalışıyor ve çıkıyor. Bu arada 1000 ms doluyor, cbFunction callback queue’ya geçiyor.
  • Event loop stack’in boş olduğunu görünce cbFunction’ı stack’e alıyor. Fonksiyon konsola “Callback Function” yazıp çıkıyor ve stack yine boş kalıyor.

Kaynaklar