Node.js, asenkron yapısıyla bilinen ve büyük ölçekli uygulamalarda verimlilik sağlayan popüler bir JavaScript çalışma zamanı ortamıdır. Bu yazıda, Node.js'in mikro görev kuyrukları ve bunların çalışma sırasını detaylı bir şekilde inceleyeceğiz. Mikro görev kuyruklarının nasıl çalıştığını anlamak, Node.js uygulamalarının performansını optimize etmek için kritik öneme sahiptir.
Node.js event loop, farklı türde görevlerin yürütüldüğü altı ana kuyruktan oluşur:
Next Queue: process.nextTick tarafından oluşturulan görevlerin saklandığı kuyruk.
Promise Queue: Promise.resolve().then ile oluşturulan görevlerin saklandığı kuyruk.
Timer Queue: setTimeout ve setInterval gibi zamanlayıcı fonksiyonları tarafından oluşturulan görevlerin saklandığı kuyruk.
Input-Output (I/O) Queue: I/O işlemleri için kullanılan kuyruk.
Check Queue: setImmediate tarafından oluşturulan görevlerin saklandığı kuyruk.
Close Queue: close event'lerinin işlenmesi için kullanılan kuyruk.
Bu kuyruklar, event loop içerisinde belirli bir sırayla işlenir ve her biri farklı türde görevleri işler.
Mikro Görev Kuyrukları:
Mikro görev kuyrukları, next queue ve promise queue olarak ikiye ayrılır. Bu kuyruklar, event loop'un belirli aşamalarında öncelikli olarak işlenir. Mikro görev kuyrukları, özellikle yüksek öncelikli küçük görevlerin hızlı bir şekilde işlenmesi için kullanılır.
Process.nextTick ve Promise.resolve:
process.nextTick: Bu yöntem, bir callback fonksiyonunu next tick kuyruğuna ekler. process.nextTick
, event loop'un bir sonraki aşamasına geçmeden önce çalıştırılacak küçük görevleri tanımlamak için kullanılır.
Kullanımı: process.nextTick(callbackFonksiyonu)
Promise.resolve().then: Bu yöntem, bir callback fonksiyonunu promise kuyruğuna ekler. Promise.resolve().then, Promise'ların tamamlanmasının ardından çalıştırılacak görevleri tanımlar.
Kullanımı: Promise.resolve().then(callbackFonksiyonu)
Örnekler ve Çıkarımlar:
İlk Örnek:
İlk örnekte, iki console.log
ifadesi ve aralarına bir process.nextTick
ifadesi eklenir. Kod şu şekildedir:
console.log(1);
process.nextTick(() => {
console.log('This is process.nextTick callback');
});
console.log(2);
Sonuç: İlk olarak senkron console.log
ifadeleri çalıştırılır ve ardından process.nextTick
içindeki callback fonksiyonu çalıştırılır. Bu durum, senkron JavaScript kodunun, asenkron koddan önce çalıştığını gösterir. Yani, process.nextTick
fonksiyonu, çağrı yığını tamamen boşaldıktan sonra çalışır.
İkinci Örnek:
İkinci örnekte, process.nextTick
ve Promise.resolve().then
ifadeleri birlikte kullanılır:
Promise.resolve().then(() => {
console.log('This is Promise.resolve callback');
});
process.nextTick(() => {
console.log('This is process.nextTick callback');
});
Sonuç: process.nextTick
içindeki callback fonksiyonları, promise kuyruğundakilerden önce çalışır. Yani, next tick kuyruğundaki tüm callback'ler, promise kuyruğundakilerden önceliklidir.
Gelişmiş Örnek:
İç içe process.nextTick
ve Promise.resolve().then
ifadeleri kullanılarak daha karmaşık bir yapı oluşturulur. Kod şu şekildedir:
process.nextTick(() => console.log("process.nextTick 1"));
process.nextTick(() => {
console.log("process.nextTick 2");
process.nextTick(() =>
console.log("next tick içinde iç next tick")
);
});
process.nextTick(() => console.log("process.nextTick 3"));
Promise.resolve().then(() => console.log("Promise.resolve 1"));
Promise.resolve().then(() => {
console.log("Promise.resolve 2");
process.nextTick(() =>
console.log("Promise then bloğu içinde iç next tick")
);
});
Promise.resolve().then(() => console.log("Promise.resolve 3"));
Sonuç: İlk olarak, process.nextTick
içindeki callback fonksiyonları çalıştırılır. İç içe olan process.nextTick
fonksiyonları, dıştakiler tamamlanana kadar çalıştırılmaz. Sonrasında, Promise.resolve().then
içindeki callback fonksiyonları çalıştırılır. Bu durum, next tick kuyruğunun promise kuyruğuna göre öncelikli olduğunu bir kez daha doğrular.
Önemli Notlar:
process.nextTick
'in aşırı kullanımı, event loop’un diğer bölümlerinin çalışmasını engelleyebilir. Bu, I/O kuyruğunun çalışmasını engelleyerek performans sorunlarına yol açabilir. process.nextTick
, iki ana amaç için kullanılmalıdır:
Kullanıcıların hataları işlemesine, gereksiz kaynakları temizlemesine veya isteği yeniden denemesine izin vermek.
Çağrı yığını çözüldükten ancak event loop devam etmeden önce bir callback çalıştırmak.
Sonuç:
Node.js'te mikro görev kuyrukları ve bunların çalışma sırasını anlamak, performansı optimize etmek ve daha verimli asenkron kod yazmak için kritik öneme sahiptir. process.nextTick
ve Promise.resolve().then
gibi yöntemlerin nasıl çalıştığını ve event loop içerisinde nasıl önceliklendirildiklerini bilmek, geliştiricilerin daha etkili Node.js uygulamaları yazmalarına yardımcı olur. Bu bilgiler, Node.js'in asenkron doğasını daha iyi kavramak ve uygulamalarınızda daha verimli çözümler üretmek için temel oluşturur.