Event Loop In Js
Herkese Merhaba,
Bu yazımda yine mülakatlarda çok sorulan sorulardan biri olan Event Loop konusundan bahsetmek istedim.
Bunun için öncelikle biraz JavaScript’in yapısından bahsedelim.
Javascript yapı olarak
- Synchronous
- Blocking
- Single Threaded
bir dildir. ( Bazı kavramları türkçeye çevirmeden belirteceğim )
Bu maddeleri açıklayacak olursak;
Synchronous: Kodlar yukarıdan ağaşıya doğru işlenir.
Blocking: Senkron yapısından dolayı fonksiyonlar sıra ile çalışacaktır. Bir fonksiyonun görevi tamamlanmadan diğerine geçmeyecektir. Bu da tarayıcıda donma gibi problemlere yol açacaktır. Tarayıcının devam etmesini engelleyecektir.
Single Threaded: Javascript aynı anda sadece bir görev yerine getirebilir.
Peki aynı anda birden fazla işlem yapmamız gerekiyorsa ve bu işlemlerin birbirini beklememesi gerekiyorsa ne yapmalıyız ? Örneğin bir datadan veriler alıp onun üzerinden sonuçlar almamız gerektiğinde verilerin getirilmesini beklemeliyiz ve ardından verilere sahip olduğumuzda kodu yürütmeye devam edebiliriz. Ama bu biraz zaman alabilir. Bu işlemi asenkron hale getirmenin bir yolunu bulmalıyız. Peki nasıl ?
Bunun için JavaScript tek başına yeterli değildir. Bu noktada ise web tarayıcıları devreye girer. Web tarayıcıları, bir tür olay meydana geldiğinde eşzamansız ( asenkron ) olarak çağrılması gereken işlevleri kaydetmemize izin veren fonksiyon ve API’leri tanımlar. Bu bir zamanın geçişi ( setInterval, setTimeOut), kullanıcıların fare ile etkileşimi (addEventListener) veya verilerin ağ üzerinden gelmesi (callbacks, promises , async-await) olabilir.
Bu demektir ki kodumuz aynı anda birkaç şeyi herhangi bir şeyi engellemeden ya da durdurmadan yapabilir.
Burada önemli bir bilgi daha vermek gerekirse zamanlayıcılar ( timers ) ve intervaller JavaScriptin kendisinin bir parçası değildir. Bunlar JavaScriptin kolayca erişebildiği tarayıcı tarafından sağlanan özelliklerdir. Fetch yapısı da ağ isteklerini gerçekleştirmenizi sağlayan bir web api’sidir.
Js Engine
Şimdi JavaScript motoruna biraz bakalım. Öncelikle bunu hazırladığım bir görsele yansıtacağım.
Görseli biraz açıklayacak olursak, JavaScipt’te tanımladığımız değişkenler ve fonksiyonlar bildiğimiz üzere JavaScript hafızasına kaydedilir. (Heap Memory). Kodu her çalıştırmamızda ise fonksiyonlarımız Call Stack alanına gönderilir ve işlevleri tamamlandığında ise Call Stack’ten çıkarılır.
Web Api kısmından yukarıda bahsetmiştim. setTimeOut, promise, fetch gibi yapılar JavaScriptin kendisinin bir parçası değildir. Bunlar JavaScriptin kolayca erişebildiği tarayıcı tarafından sağlanan Web Apilerdir.
Dördüncü kısmımız, Callback Queue olarak adlandırılan kısımdır. İlk giren ilk çıkar yapısı ile çalışır. Beşinci ve son kısım ise, Event Loop’tur. Event Loop’un yalnızca bir işi vardır. Call Stack’in boş olup olmadığını kontrol etmek ve boşsa kuyruktaki bir ögeyi buraya göndermek.
Async Event Loop
İlk etapta yine görseller üzerinden ve örnek bir kodla sırası ile işlemlerin nasıl işlediğine bakalım
- İlk kodumuz konsola First yazdırıyor. Birinci resimde İlk etapta Call Stack’te global fonksiyonumuz oluştu. Sonrasında log fonksiyonu Call Stack’e gönderildi.
- İkinci resimde logumuzun çıktısı konsola First olarak geldi ve geldiği anda işi bittiği için Call Stack’ten atıldı. Ve Javascript bir sonraki satırda yer alan setTimeOut’a geçti ve onu Call Stack’e gönderdi.
- Üçüncü resme geçelim. setTimeOut’un JavaScript’te bir özellik olmadığını söylemiştik. Bu nedenden dolayı callback fonksiyon ve süresi, bir tarayıcı özelliği olan Web Api’ye devredilir. Ve JavaScript, Call Stack’ten setTimeOut fonksiyonunu çıkarır. Çünkü işi tamamlanmıştır. Web Api, zamanlayıcısını arka planda 2 saniyeliğine başlatır. Bu esnada JavaScript’te konsola Third yazdıran üçüncü koda geçer ve log fonksiyonunu Call Stack’e alır.
- Dördüncü resme baktığımızda konsola Third çıktısı gelir ve işi bittiği için Call Stack’ten atılır. Bu esnada setTimeOut’un süresi de dolmuştur ve kodun çalışması için Call Stack’e gönderilmesi gerekmektedir. Ancak Web Api’ler direk olarak Call Stack’e gönderme yapamaz. Bunun yerine Web Api callback fonksiyonunu Callback Queue’ye gönderir. İşte bu noktada fonksiyonun Call Stack’e gönderilip gönderilmeyeceğine karar veren kısım Event Loop’tur. Event Loop sürekli olarak Call Stack’in boş olup olmadığını kontrol eder. Tek görevi budur. Ve bu bir döngü halinde çalışır.
- Beşinci resme gelelim. Callback fonksiyonumuz Callback Queue’dan boş olan Call Stack’e gönderildi. Ve setTimeOut içinde de konsola Second yazdıran bir kodumuz var. Bu yüzden log fonksiyonumuz da Call Stack’e gönderildi.
- Son resme geçtik. Ve JavaScript konsola Second yazdırdı. Yazdırdıktan sonra ise işi bittiği için log fonksiyonunu Call Stack’ten attı. setTimeOut içinde başka kod parçaçığı olmadığı için callback fonksiyonunu da Call Stack’ten attı. Aynı zamanda çalıştıracak başka kod da olmadığı için global fonksiyon da Call Stackten silindi.
Bu konu ile ilgili aşağıya çok güzel bir video bırakacağım. Tüm yazdıklarım bu videodan alınmıştır. Bir nevi Türkçeye çevirdim de denebilir. İzlemenizi şiddetle tavsiye ederim. Okuduğunuz için teşekkür ederim :)