Tarayıcıdaki JavaScript’in tek iş parçacıklı yapısı yüzünden asenkron kodlar devreye girince nasıl yönetiliyor? Call Stack, Task Queue ve Microtask Queue arasındaki ilişkiyi açıklayabilir misiniz? Buradaki öncelik sırası (örneğin Promise’lerin setTimeout’dan önce çalışması) nasıl belirleniyor? Tarayıcı motorları bunun için hangi optimizasyonları uyguluyor?
Event Loop’un JavaScript’teki rolü nedir?
👁️ 0 görüntüleme💬 2 cevap❤️ 0 beğeni
2 Cevap
JavaScript’in tek iş parçacıklı (single-threaded) doğasını telafi etmek için tasarlanan Event Loop mekanizması, aslında JS motorlarının en zekice tasarlanmış bileşenlerinden biri. Bu işleyişin nasıl olduğunu anlarken Call Stack, Task Queue ve Microtask Queue’nun senkronizasyonunu anlamak kritik, ancak tarayıcı motorlarının bu yapıyı optimize etmek için neler yaptığına da dikkat etmek gerekiyor.
Call Stack’in en tepesinde senkron kodlar çalışırken, asenkron olaylar (setTimeout, Promise, DOM olayları vb.) doğrudan stack’e girmezler. Bunun yerine, tarayıcı API’ları (örneğin Web APIs) bunu Task Queue’ya (veya Macro Task Queue) ekler. Burada dikkat edilmesi gereken nokta: Microtask Queue (Promise callbacks, MutationObserver, queueMicrotask) Task Queue’dan **önce** işleniyor. Bu öncelik, JS motorlarının performans optimizasyonundan kaynaklanıyor. Microtask’ların hızlıca temizlenmesi, uygulama durumunu anında güncelleyerek UI akıcılığını koruyor. Örneğin Promise.then’in setTimeout’dan önce çalışmasının sebebi bu.
Tarayıcı motorları (V8, SpiderMonkey vb.) Event Loop’u optimize ederken, özellikle IO-bound işlemleri en aza indirmeye çalışıyor. Örneğin, Node.js’de libuv’un kullanılmasıyla tarayıcıdan farklı olarak timer’ların yönetimi daha verimli hale geliyor. Ayrıca, Microtask Queue’nun sürekli olarak tarandığı "Yield" mekanizmaları sayesinde tarayıcılar, UI render’larını bloke etmemek için periyodik olarak Event Loop’a müdahale edebiliyor. Yine de, bu yapının modern JS uygulamalarında neden sık sık "Zalgo" örneğiyle karşılaşıldığını anlamak da önemli—bazı geliştiriciler, Microtask/Task Queue farklarını göz ardı ederek beklenmedik davranışlara yol açıyorlar. Peki, sizce bu öncelik mekanizmasını daha basitleştirmek mümkün mü, yoksa Event Loop’un karmaşıklığı aslında JS’in en güçlü yanlarından mı biri?
Event Loop’un tek thread’li JavaScript dünyasında nasıl bir kurtarıcı gibi çalıştığını geçtiğimiz CTF’lerde exploit yazarken daha net gördüm aslında. Mesela geçen sene bir WebSocket tabanlı bir zafiyette, `setTimeout`’u manipüle ederek Promise’leri tetikleyip stack overflow’a sebep olmuştuk — orada Event Loop’un nasıl bir sıra dışı durumda kilitlendiğini birebir gözlemleme fırsatım oldu. Hele Microtask Queue’u unutmamak lazım; dom manipülasyonlarıyla oynarken bile `queueMicrotask()` kullanıp task’ları manuel tetiklemek performans kazancı sağlıyordu, sanki motoru "yavaşlatıyordum" ama aslında optimize etmiş oluyordum.
Priority konusunu hep karıştırıyordum ama bir ara Node.js’in event loop’unu debugger ile adım adım izlerken Event Loop’un spesifikasyonunu (8 fazdan oluşan tur seri) ve microtask’lerin en tepede nasıl devreye girdiğini net şekilde anladım. Modern tarayıcılarda (Chrome’un V8’i, Firefox’un SpiderMonkey’i) microtask’lerin sürekli exec edilmesini sağlamak için sürekli bir "microtask checkpoint" mekanizması var — sanki sistem "acaba yeni bir microtask geldi mi?" diye sürekli tetikte bekliyor gibisi. Bu da bize, callback’lerinizin birbirini tetikleyecek şekilde yapılandırılması durumunda performansı ciddi şekilde artırabiliyor.
Tartışmaya katılmak için giriş yap
Giriş Yap