avatar
·4 dk okuma
Node.js'de Timer Queue

Node.js'de Timer Queue

Node.js, yüksek performans ve ölçeklenebilirlik sunan, olay güdümlü bir asenkron çalışma modeline sahip bir JavaScript çalışma zamanıdır. Asenkron çalışma modeli, Node.js'in yüksek trafik altında bile hızlı ve verimli çalışmasını sağlar. Bu makalede, Node.js'in asenkron yapısını ve bu yapıdaki önemli bir kavram olan Timer Queue'yu detaylı bir şekilde inceleyeceğiz.

1. Node.js Asenkron Yapısına Giriş

Node.js, tek bir olay döngüsü (event loop) üzerinden çalışır. Bu, birden fazla işlemin aynı anda yürütülmesini sağlar ve yüksek performans sunar. Olay döngüsü, sıraya alınmış işlemleri (callback fonksiyonları) belirli bir sıra ve öncelik dahilinde yürütür. Bu sıranın anlaşılması, Node.js'de verimli asenkron kod yazmanın temelidir.

Asenkron yapının önemli bileşenleri şunlardır:

  • Call Stack (Çağrı Yığını)

  • Event Loop (Olay Döngüsü)

  • Callback Queue (Geri Çağırma Kuyruğu)

  • Microtask Queue (Mikro Görev Kuyruğu)

  • Timer Queue (Zamanlayıcı Kuyruğu)

  • I/O Queue (Giriş/Çıkış Kuyruğu)

2. Timer Queue Nedir?

Timer Queue, belirli bir süre sonra yürütülmesi gereken callback fonksiyonlarını barındıran bir veri yapısıdır. Timer Queue'ya callback fonksiyonları eklemek için setTimeout veya setInterval fonksiyonları kullanılır. Bu kuyruk, diğer microtask kuyruklarına göre daha düşük bir önceliğe sahiptir.

setTimeout ve setInterval fonksiyonlarının sözdizimi şu şekildedir:

setTimeout(callbackFunction, delay);
setInterval(callbackFunction, delay);
  • callbackFunction: Gecikme süresi sona erdiğinde yürütülecek fonksiyon.

  • delay: Milisaniye cinsinden gecikme süresi.

3. Timer Queue ile Örnekler

Bu bölümde, Timer Queue'nun nasıl çalıştığını ve öncelik sırasını anlamak için birkaç örnek yapacağız.

Örnek 1: Basit setTimeout Kullanımı ve Microtask Kuyrukları ile Karşılaştırma

İlk örneğimizde, setTimeout, process.nextTick ve Promise.resolve kullanarak farklı kuyrukların öncelik sırasını test edeceğiz.

setTimeout(() => console.log("setTimeout 1"), 0);
setTimeout(() => console.log("setTimeout 2"), 0);
setTimeout(() => console.log("setTimeout 3"), 0);

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"));

Bu kodu çalıştırdığımızda, beklediğimiz çıktı:

process.nextTick 1
process.nextTick 2
next tick içinde iç next tick
process.nextTick 3
Promise.resolve 1
Promise.resolve 2
Promise.resolve 3
Promise then bloğu içinde iç next tick
setTimeout 1
setTimeout 2
setTimeout 3

Bu örnek, process.nextTick ve Promise çözümlemelerinin, timer queue'daki setTimeout fonksiyonlarından önce yürütüldüğünü gösterir.

Örnek 2: İç İçe Callback Fonksiyonları

İkinci örnekte, setTimeout fonksiyonu içinde process.nextTick kullanacağız.

setTimeout(() => console.log("setTimeout 1"), 0);
setTimeout(() => {
    console.log("setTimeout 2");
    process.nextTick(() =>
        console.log("setTimeout içinde iç next tick")
    );
}, 0);
setTimeout(() => console.log("setTimeout 3"), 0);

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"));

Bu kodu çalıştırdığımızda, beklediğimiz çıktı:

process.nextTick 1
process.nextTick 2
next tick içinde iç next tick
process.nextTick 3
Promise.resolve 1
Promise.resolve 2
Promise.resolve 3
Promise then bloğu içinde iç next tick
setTimeout 1
setTimeout 2
setTimeout içinde iç next tick
setTimeout 3

Bu örnek, setTimeout içinde process.nextTick kullanıldığında, nextTick fonksiyonunun timer queue'daki diğer callback fonksiyonlarından önce yürütüldüğünü gösterir.

timer queue image
Örnek 3: Farklı Gecikme Süreleri ile setTimeout

Son örnekte, farklı gecikme sürelerine sahip setTimeout fonksiyonlarını kullanacağız.

setTimeout(() => console.log("setTimeout 1"), 1000);
setTimeout(() => console.log("setTimeout 2"), 500);
setTimeout(() => console.log("setTimeout 3"), 0);

Bu kodu çalıştırdığımızda, beklediğimiz çıktı:

setTimeout 3
setTimeout 2
setTimeout 1

Bu örnek, en kısa gecikme süresine sahip setTimeout fonksiyonunun önce yürütüldüğünü gösterir.

4. Timer Queue'nun FIFO Sırası

Timer Queue, aslında bir Min Heap veri yapısıdır. Ancak, anlamayı kolaylaştırmak için FIFO (First In, First Out) sırasıyla çalıştığını düşünebiliriz. Bu, en kısa gecikme süresine sahip callback fonksiyonlarının önce sıraya alınmasını ve yürütülmesini sağlar.

Sonuç

Bu makalede, Node.js'in asenkron yapısını ve Timer Queue'nun nasıl çalıştığını detaylı bir şekilde inceledik. Timer Queue, Node.js'in olay güdümlü asenkron çalışma modelinde önemli bir rol oynar ve doğru anlaşıldığında asenkron kod yazmayı daha etkili hale getirir. Timer Queue'nun mikro görev kuyruklarından daha düşük önceliğe sahip olduğunu ve FIFO sırasına göre çalıştığını öğrendik. Bu bilgiler, Node.js uygulamalarında daha verimli ve öngörülebilir asenkron işlemler gerçekleştirmek için kritik öneme sahiptir.