Node.js, event-driven yapısı ve asenkron çalışma mantığı ile yüksek performanslı ve ölçeklenebilir uygulamalar geliştirmeye olanak tanır. Bu yapı içerisinde, event loop ve çeşitli callback kuyrukları (queues) büyük bir öneme sahiptir. Bu makalede, Node.js'deki check queue'yu ve diğer ilgili kuyrukları detaylı bir şekilde inceleyeceğiz. Ayrıca, çeşitli örneklerle bu kavramları pekiştireceğiz.
Node.js'deki event loop, ana iş parçacığını bloklamadan çeşitli asenkron işlemleri yönetir. Event loop'un farklı fazları vardır ve her faz belirli türdeki callback'leri işler:
Senkron Kod: İlk olarak çalıştırılan kod parçasıdır. Bu kod doğrudan çalıştırılır ve bloklama potansiyeline sahiptir.
Micro Task Queues: process.nextTick ve Promise.resolve gibi işlemlerle eklenen görevler bu kuyrukta yer alır. Mikro görevler, senkron koddan hemen sonra çalıştırılır ve yüksek önceliğe sahiptir.
Timer Queue: setTimeout ve setInterval gibi zamanlayıcılarla eklenen geri çağırma fonksiyonları bu kuyrukta toplanır. Belirtilen gecikme süresi tamamlandığında bu kuyruktaki görevler çalıştırılır.
I/O Queue: Dosya okuma/yazma, ağ işlemleri gibi I/O operasyonları tamamlandığında geri çağırma fonksiyonları bu kuyrukta yer alır ve zamanlayıcı kuyruğundan sonra çalıştırılır.
I/O Polling: I/O olaylarını işler ve yeni gelen I/O olaylarını bekler.
Check Kuyruğu: setImmediate
callback'lerini işler.
Close Kuyruğu: Kapatma işlemleriyle ilgili callback'leri işler, örneğin socket.on('close', ...)
.
IO polling ve check queue, Node.js'deki asenkron işlemleri anlamak için kritik öneme sahiptir. IO polling, dosya okuma/yazma gibi I/O işlemlerinin tamamlanmasını bekler. Bu işlemler tamamlandığında, ilgili callback'ler IO queue'ya eklenir. Check queue ise setImmediate
tarafından eklenen callback'leri işler.
Önceki videolarımızda, IO polling'in IO queue ve check queue arasında nasıl gerçekleştiğini anladık. Örneğin, readFile
işlemi sonrasında setImmediate
'in kilitlenme sırasını inceledik. Şimdi bu konuyu daha derinlemesine inceleyelim.
Bu örnekte, çeşitli callback kuyruklarının nasıl çalıştığını gözlemleyeceğiz.
Kod:
const fs = require('fs');
fs.readFile(__filename, (err, data) => {
console.log('Read File Callback');
setImmediate(()=> {
console.log("ReadFile içinde Set Immediate Callback");
})
});
process.nextTick(() => {
console.log('Next Tick Callback');
});
Promise.resolve().then(() => {
console.log('Promise Callback');
});
setTimeout(() => {
console.log('Set Timeout Callback');
}, 0);
Bu kodda, readFile
, setImmediate
, process.nextTick
, Promise.resolve
ve setTimeout
callback'lerinin çalışma sırasını inceleyeceğiz.
Beklenen Çıktı:
Next Tick Callback
Promise Callback
Set Timeout Callback
Read File Callback
ReadFile içinde Set Immediate Callback
Bu örnekten çıkarabileceğimiz önemli bir bilgi, micro task queue (process.nextTick ve Promise.resolve) callback'lerinin diğer tüm callback kuyruklarından önce çalıştığıdır.
readFile
İçinde process.nextTick
ve Promise.resolve
Bu örnekte, readFile
callback'i içinde setImmediate
'den sonra process.nextTick
ve Promise.resolve
ekleyeceğiz.
Kod:
const fs = require("fs");
fs.readFile(__filename, (err, data) => {
console.log("Read File Callback");
setImmediate(() => console.log("ReadFile içinde Set Immediate Callback"));
process.nextTick(() => {
console.log("ReadFile içinde Next Tick Callback");
});
Promise.resolve().then(() => {
console.log("ReadFile içinde Promise Callback");
});
});
process.nextTick(() => {
console.log("Next Tick Callback");
});
Promise.resolve().then(() => {
console.log("Promise Callback");
});
setTimeout(() => {
console.log("Set Timeout Callback");
}, 0);
Bu değişiklikle, readFile
callback'i içinde eklenen process.nextTick
ve Promise.resolve
callback'lerinin nasıl çalıştığını gözlemleyeceğiz.
Beklenen Çıktı:
Next Tick Callback
Promise Callback
Set Timeout Callback
Read File Callback
ReadFile içinde Next Tick Callback
ReadFile içinde Promise Callback
ReadFile içinde Set Immediate Callback
Bu örnekten çıkarabileceğimiz bilgi, readFile
içinde eklenen micro task queue callback'lerinin, diğer micro task queue callback'lerinden sonra çalıştığıdır.
setImmediate
Çağrısı ve process.nextTick
ile Promise.resolve
Bu örnekte, üç setImmediate
çağrısı yapacağız ve ikinci setImmediate
içinde process.nextTick
ve Promise.resolve
ekleyeceğiz.
Kod:
setImmediate(() => console.log("Set Immediate Callback 1"));
setImmediate(() => {
console.log("Set Immediate Callback 2");
process.nextTick(() => {
console.log("Set Immediate 2 içinde Next Tick Callback");
});
Promise.resolve().then(() => {
console.log("Set Immediate 2 içinde Promise Callback");
});
});
setImmediate(() => console.log("Set Immediate Callback 3"));
Bu kod ile, check queue callback'leri arasında micro task queue callback'lerinin çalıştığını gözlemleyeceğiz.
Beklenen Çıktı:
Set Immediate Callback 1
Set Immediate Callback 2
Set Immediate 2 içinde Next Tick Callback
Set Immediate 2 içinde Promise Callback
Set Immediate Callback 3
Bu örnek, micro task queue callback'lerinin check queue callback'lerinin arasında çalıştığını gösterir.
setTimeout
ve setImmediate
AnomalisiBu örnekte, setTimeout
(0ms gecikme ile) ve setImmediate
çağrısı yapacağız.
Kod:
setTimeout(() => console.log("Set Timeout Callback 1"), 0);
setImmediate(() => console.log("Set Immediate Callback 1"));
Bu örnek, setTimeout
ve setImmediate
sırasının her zaman aynı olmadığını gösterir. IO queue ile ilgili önceki videoda açıklanan nedenlerden dolayı, bu işlemlerin sırası garanti edilemez.
Beklenen Çıktı: Çalıştırıldığında, çıktı değişebilir:
Set Timeout Callback 1
Set Immediate Callback 1
veya
Set Immediate Callback 1
Set Timeout Callback 1
Uzun süreli bir for
döngüsü eklenirse, setTimeout
her zaman setImmediate
'den önce çalışır.
Bu makalede, Node.js'deki check queue ve ilgili diğer kuyrukların nasıl çalıştığını detaylı bir şekilde inceledik. Yapılan örnekler, bu kavramları anlamamıza yardımcı oldu ve Node.js'nin asenkron çalışma mantığını pekiştirdi. Check queue, event loop ve micro task queue gibi kavramlar, Node.js ile performanslı ve ölçeklenebilir uygulamalar geliştirmek için kritik öneme sahiptir.