Node.js'te zamanlayıcılar üç global fonksiyonla kurulur: setTimeout(fn, ms) bir işi belirli bir süre sonra bir kez, setInterval(fn, ms) her ms milisaniyede bir tekrar tekrar, setImmediate(fn) ise event loop'un o turundaki I/O geri çağırmalarından hemen sonra çalıştırır. Tarayıcıdan farklı olarak setTimeout ve setInterval bir sayı değil, ref(), unref(), refresh() gibi metotları olan bir Timeout nesnesi döndürür. Promise ile beklemek için node:timers/promises modülü vardır: await setTimeout(1000).
Bu yazıda node:timers API'sini, süre değerinin sınırlarını, sürecin zamanlayıcı yüzünden kapanmamasını önleyen unref()'i, refresh() ile süreyi yeniden başlatmayı, timers/promises ile async/await ve for await kullanımını, AbortController ile iptali Node.js v26.13.0 üzerinde çalıştırılmış örneklerle anlatıyoruz. Zamanlayıcıların event loop'un hangi fazında çalıştığı process.nextTick ve setImmediate yazısının konusudur; serinin tamamı için Node.js öğrenme rehberi sayfasına bakabilirsiniz.
node:timers modülü ve global fonksiyonlar

Zamanlayıcı fonksiyonları globaldir; kullanmak için require('node:timers') veya import yazmanız gerekmez. Belgelere göre API tarayıcılardaki zamanlayıcılara benzer, ancak iç yapısı Node.js event loop'u üzerine kuruludur ve farklıdır. Modül Stability: 2 - Stable olarak işaretlidir. node:timers modülünü açıkça içe aktarmak, aynı fonksiyonlara modül üzerinden erişmek isteyen kodlar için mümkündür; Promise döndüren sürümler ise ayrı bir alt modüldedir: node:timers/promises.
setTimeout(callback[, delay[, ...args]]) imzasında üçüncü ve sonraki argümanlar, geri çağırma çalıştığında ona aynen iletilir. Bu sayede ek bir ok fonksiyonu yazmadan parametre geçebilirsiniz. Dönen değer bir Timeout nesnesidir:
const t = setTimeout((ad, adet) => {
console.log(`${ad} için ${adet} hatırlatma gönderildi`);
}, 50, 'Mehmet', 3);
console.log(typeof t, t.constructor.name);
console.log('hasRef:', t.hasRef());
console.log('sayıya çevrilebilir mi:', typeof +t === 'number');
// çıktı: object Timeout
// çıktı: hasRef: true
// çıktı: sayıya çevrilebilir mi: true
// çıktı: Mehmet için 3 hatırlatma gönderildiTimeout nesnesinin Symbol.toPrimitive metodu vardır; +t gibi bir dönüşüm onu bir sayıya çevirir. Belgelere göre bu sayı, zamanlayıcıyı iptal etmek için clearTimeout()'a verilebilir ve tarayıcı kodlarıyla uyumluluğu artırır. Sınırı da belgelenmiştir: bu sayı yalnızca zamanlayıcının oluşturulduğu thread'de geçerlidir; bir worker thread içinde kullanmak için önce doğru thread'e iletilmesi gerekir.
Gecikme değerinin kuralları
delay parametresinin varsayılanı 1'dir. Belgelere göre değer 2147483647'den büyükse, 1'den küçükse ya da NaN ise 1 olarak ayarlanır; tam sayı olmayan değerler tam sayıya kırpılır. Node.js v26.13.0 bu durumlarda stderr'e ayrıca birer uyarı yazıyor:
const bas = Date.now();
setTimeout(() => console.log('-5 ms bekledi mi?', Date.now() - bas < 50), -5);
setTimeout(() => console.log('NaN gecikme de 1 ms olur'), NaN);
setTimeout(() => console.log('2**31 ms yerine hemen çalıştı'), 2 ** 31);
// çıktı: -5 ms bekledi mi? true
// çıktı: NaN gecikme de 1 ms olur
// çıktı: 2**31 ms yerine hemen çalıştı
// stderr: (node:8996) TimeoutNegativeWarning: -5 is a negative number.
// stderr: Timeout duration was set to 1.
// stderr: (node:8996) TimeoutNaNWarning: NaN is not a number.
// stderr: Timeout duration was set to 1.
// stderr: (node:8996) TimeoutOverflowWarning: 2147483648 does not fit into a 32-bit signed integer.
// stderr: Timeout duration was set to 1.Son satır pratikte en tehlikeli olanıdır: yaklaşık 24,8 günden (2147483647 ms) uzun bir süre verirseniz zamanlayıcı beklemek yerine hemen çalışır. Uzun süreli planlama (örneğin bir ay sonra çalışacak bir iş) için zamanlayıcı değil, bir zamanlanmış görev sistemi kullanın. Uyarıların hangi satırdan geldiğini görmek için --trace-warnings bayrağını kullanabilirsiniz.
clearTimeout, clearInterval ve clearImmediate
Her zamanlayıcı fonksiyonunun bir iptal karşılığı vardır. clearTimeout() ve clearInterval(), Timeout nesnesini ya da onun sayı veya string biçimindeki ilkel değerini kabul eder; clearImmediate() ise Immediate nesnesini alır. Eski timeout.close() metodu Legacy olarak işaretlidir ve yerine clearTimeout() önerilir.
setTimeout(() => console.log('1.5 ms gecikmeli zamanlayıcı çalıştı'), 1.5);
clearTimeout(setTimeout(() => console.log('görünmez'), 10));
const t = setTimeout(() => console.log('görünmez 2'), 10);
clearTimeout(String(+t));
console.log('iki zamanlayıcı iptal edildi');
// çıktı: iki zamanlayıcı iptal edildi
// çıktı: 1.5 ms gecikmeli zamanlayıcı çalıştısetInterval sizin durdurmanızı bekler; çoğu zaman geri çağırmanın içinden, bir koşul sağlandığında clearInterval() çağrılır:
let tur = 0;
const id = setInterval(() => {
tur++;
console.log('tur', tur);
if (tur === 3) {
clearInterval(id);
console.log('interval durduruldu');
}
}, 20);
// çıktı: tur 1
// çıktı: tur 2
// çıktı: tur 3
// çıktı: interval durdurulduNode.js v24.2.0'dan beri Timeout ve Immediate nesnelerinin [Symbol.dispose]() metodu deneysel olmaktan çıktı (YAML kaydı: "No longer experimental"). Bu metot zamanlayıcıyı iptal eder; böylece using bildirimiyle, blok bittiğinde zamanlayıcının otomatik iptal edilmesini sağlayabilirsiniz:
{
using t = setTimeout(() => console.log('bu hiç yazılmaz'), 10);
console.log('blok içinde, zamanlayıcı kuruldu');
}
console.log('blok bitti, zamanlayıcı iptal edildi');
// çıktı: blok içinde, zamanlayıcı kuruldu
// çıktı: blok bitti, zamanlayıcı iptal edildisetImmediate() ve Immediate nesnesi
setImmediate(callback[, ...args]) bir Immediate nesnesi döndürür ve geri çağırmayı I/O olaylarının geri çağırmalarından sonra çalışacak şekilde planlar. Belgelerdeki kurallar şunlardır: birden çok setImmediate() çağrısı oluşturulma sırasıyla kuyruğa girer; her event loop turunda kuyruğun tamamı işlenir; çalışan bir immediate geri çağırmasının içinden kurulan yeni immediate ise bir sonraki tura kalır. Immediate nesnesi de ref(), unref(), hasRef() ve [Symbol.dispose]() metotlarına sahiptir; iptal için clearImmediate() kullanılır. Üç zamanlayıcı fonksiyonunun hepsinde callback bir fonksiyon değilse TypeError fırlatılır; YAML kaydına göre v18.0.0'dan beri bu hatanın kodu ERR_INVALID_CALLBACK yerine ERR_INVALID_ARG_TYPE'dır. Hata kodlarının genel listesi için ERR_* hata kodları yazısına bakabilirsiniz.
ref() ve unref(): süreci zamanlayıcı yüzünden açık tutmamak

Varsayılan olarak aktif bir zamanlayıcı event loop'u canlı tutar; yani bekleyen bir setInterval varken süreç kendiliğinden kapanmaz. timeout.unref() çağırdığınızda zamanlayıcı artık döngüyü açık tutmaz: başka bir iş kalmamışsa süreç, geri çağırma hiç çalışmadan kapanabilir. ref() bu davranışı geri alır, hasRef() mevcut durumu söyler. Her iki metot da birden çok kez çağrıldığında ek bir etki yapmaz.
const kalpAtisi = setInterval(() => console.log('ping'), 1000);
kalpAtisi.unref();
setTimeout(() => console.log('asıl iş bitti'), 30);
// çıktı: asıl iş bitti
// (süreç burada kapanır; unref edilen interval hiç çalışmadı)Bu desen; arka plan metrikleri, bağlantı havuzu temizliği ya da periyodik önbellek yenileme gibi "varsa çalışsın ama süreci tek başına ayakta tutmasın" türündeki işler için uygundur. Bir sunucu dinlemeye devam ettiği sürece süreç zaten açık kalır; sunucu kapandığında ise unref edilmiş zamanlayıcılar kapanışı engellemez. Zarif kapanma (graceful shutdown) senaryoları için cluster ve PM2 yazısına bakabilirsiniz.
refresh(): süreyi yeni nesne oluşturmadan baştan başlatmak
timeout.refresh(), zamanlayıcının başlangıç zamanını şu ana çeker ve geri çağırmayı, ilk verilen süre kadar sonraya yeniden planlar. Belgeler bunun yeni bir JavaScript nesnesi ayırmadan zamanlayıcıyı tazelemeye yaradığını söyler. Geri çağırması zaten çalışmış bir zamanlayıcıda kullanılırsa zamanlayıcıyı yeniden etkinleştirir. Hareketsizlik süresi (idle timeout) için kullanışlıdır:
const bas = Date.now();
const bosta = setTimeout(() => {
console.log('oturum kapandı, en az 220 ms geçti mi:', Date.now() - bas >= 220);
}, 100);
// Kullanıcı 60. ve 120. ms'de işlem yapıyor: süre her seferinde baştan başlar
setTimeout(() => bosta.refresh(), 60);
setTimeout(() => bosta.refresh(), 120);
// çıktı: oturum kapandı, en az 220 ms geçti mi: truesetInterval mi, özyinelemeli setTimeout mu?
Learn rehberi önemli bir farka dikkat çeker: setInterval fonksiyonu her n milisaniyede başlatır ve bir önceki çalışmanın ne zaman bittiğini hesaba katmaz. İşin süresi değişkense (örneğin ağ isteğine bağlıysa) çalışmalar birbirine yaklaşabilir ya da üst üste binebilir. Her çalışma bittikten sonra bir sonrakini planlamak isterseniz özyinelemeli setTimeout kullanın; böylece iki çalışma arasında her zaman en az belirtilen süre kadar boşluk kalır:
let calisma = 0;
function yokla() {
calisma++;
console.log('yoklama', calisma);
if (calisma < 3) setTimeout(yokla, 20);
}
setTimeout(yokla, 20);
// çıktı: yoklama 1
// çıktı: yoklama 2
// çıktı: yoklama 3node:timers/promises: await ile beklemek
node:timers/promises modülü, Promise döndüren zamanlayıcılar sunar ve v16.0.0'da deneysel olmaktan çıkmıştır. setTimeout([delay[, value[, options]]]) süre dolunca value ile çözülen bir Promise, setImmediate([value[, options]]) ise bir sonraki check fazında çözülen bir Promise döndürür. İsimler global fonksiyonlarla çakıştığı için içe aktarırken yeniden adlandırmak okunabilirliği artırır. Promise ve await kavramları için Promise yazısına bakabilirsiniz.
import { setTimeout as bekle, setImmediate as sirada } from 'node:timers/promises';
console.log('başladı');
const deger = await bekle(50, 'tamam');
console.log('50 ms sonra:', deger);
console.log('setImmediate sözü:', await sirada('sırada'));
// çıktı: başladı
// çıktı: 50 ms sonra: tamam
// çıktı: setImmediate sözü: sıradaİki fonksiyonun options nesnesi ref ve signal alır. ref: false, unref() ile aynı etkiyi yapar; signal ise bir AbortSignal ile beklemeyi iptal etmenizi sağlar.
setInterval async iterator ile periyodik iş
timersPromises.setInterval(delay, value) her delay milisaniyede value üreten bir async iterator döndürür. for await...of ile dolaşılır, break ile durdurulur. Belgelere göre ref varsayılan değeri olan true iken döngüyü canlı tutmak için iterator'ın next() metodunun açıkça ya da örtük olarak çağrılması gerekir; for await bunu sizin yerinize yapar.
import { setInterval } from 'node:timers/promises';
let i = 0;
for await (const etiket of setInterval(20, 'tik')) {
console.log(etiket, ++i);
if (i === 3) break;
}
console.log('döngüden çıkıldı, süreç kapanabilir');
// çıktı: tik 1
// çıktı: tik 2
// çıktı: tik 3
// çıktı: döngüden çıkıldı, süreç kapanabilirBu biçimin avantajı, her turdaki işi await ile bekleyebilmenizdir; döngünün gövdesi bitmeden bir sonraki değer işlenmez. Async iterator protokolünün kendisi için generator ve iterator yazısına göz atın.
Zamanlayıcıyı AbortController ile iptal etmek
Promise tabanlı setTimeout ve setImmediate için iptal yöntemi bir AbortController'dır. Belgelere göre iptal edildiğinde dönen Promise 'AbortError' ile reddedilir. Gerçek çıktı, hatanın code değerinin ABORT_ERR olduğunu da gösteriyor:
import { setTimeout as bekle } from 'node:timers/promises';
const ac = new AbortController();
setTimeout(() => ac.abort(), 20);
try {
await bekle(5000, null, { signal: ac.signal });
} catch (err) {
console.log(err.name, err.code, err.message);
}
// çıktı: AbortError ABORT_ERR The operation was abortedZaman aşımı, kullanıcı iptali ve bunların birleştirilmesi gibi iptal desenlerinin tamamını AbortController ve AbortSignal yazısında anlatıyoruz.
Deneysel scheduler API'si
node:timers/promises ayrıca scheduler.wait(delay[, options]) ve scheduler.yield() sunar. İkisi de Stability: 1 - Experimental olarak işaretlidir ve web platformu için geliştirilmekte olan Scheduling APIs taslağına dayanır. Belgelere göre scheduler.wait(delay, options), setTimeout(delay, undefined, options) ile; scheduler.yield() ise argümansız setImmediate() ile eşdeğerdir. Ek bir bayrak gerektirmeden çalışıyorlar, ancak deneysel oldukları için üretim kodunda kararlı karşılıklarını tercih edin.
import { scheduler } from 'node:timers/promises';
await scheduler.wait(20);
console.log('scheduler.wait bitti');
await scheduler.yield();
console.log('scheduler.yield bitti');
// çıktı: scheduler.wait bitti
// çıktı: scheduler.yield bittiFonksiyon ve modül özeti
| API | Döndürdüğü | İptal | Not |
|---|---|---|---|
| setTimeout(fn, ms, ...args) | Timeout | clearTimeout | Bir kez çalışır |
| setInterval(fn, ms, ...args) | Timeout | clearInterval | Bitiş süresini beklemeden tekrarlar |
| setImmediate(fn, ...args) | Immediate | clearImmediate | check fazında çalışır |
| timers/promises setTimeout(ms, v, opts) | Promise | signal seçeneği | v ile çözülür |
| timers/promises setImmediate(v, opts) | Promise | signal seçeneği | Bir sonraki check fazında |
| timers/promises setInterval(ms, v, opts) | Async iterator | break veya signal | for await ile kullanılır |
| scheduler.wait / scheduler.yield | Promise | signal (wait) | Deneysel |
Sık yapılan hatalar

- Çok uzun süre vermek: 2147483647 ms'den büyük değerler 1 ms'ye düşer ve zamanlayıcı hemen çalışır. Uzun vadeli planlama için zamanlayıcı kullanmayın.
- setInterval'i hiç temizlememek: Durdurulmayan bir interval süreci sonsuza kadar açık tutar. İşi bitince
clearInterval()çağırın ya da arka plan işi iseunref()kullanın. - Değişken süreli işi setInterval ile çalıştırmak: Önceki çalışma bitmeden yenisi başlayabilir. Özyinelemeli
setTimeoutya dafor awaitiletimers/promisessetIntervalkullanın. - timers/promises setTimeout'u global setTimeout gibi çağırmak: Promise sürümünün ilk argümanı fonksiyon değil süredir.
await setTimeout(() => {}, 100)yazmak, v26.13.0'daERR_INVALID_ARG_TYPEkodlu birTypeErrorile reddedilir (The "delay" argument must be of type number). İçe aktarırkensetTimeout as beklegibi farklı bir ad kullanmak karışıklığı önler. - Zamanlayıcının tam zamanında çalışacağını varsaymak: Süre bir alt sınırdır; uzun senkron işler zamanlayıcıyı geciktirir. Testlerde gerçek zamana bağlı kalmamak için mock.timers ile sahte zamanlayıcı kullanabilirsiniz.
Sık Sorulan Sorular
Node.js'te setTimeout neden sayı yerine nesne döndürüyor?
Node.js'in zamanlayıcıları event loop üzerine kurulu ayrı bir uygulamadır ve dönen Timeout nesnesi ref(), unref(), refresh(), hasRef() gibi metotlar sunar. Tarayıcı uyumluluğu için nesne Symbol.toPrimitive ile sayıya çevrilebilir ve bu sayı clearTimeout()'a verilebilir.
JavaScript'te sleep fonksiyonu nasıl yazılır?
Node.js'te ayrıca yazmanıza gerek yoktur: import { setTimeout as sleep } from 'node:timers/promises' sonrasında await sleep(1000) bir saniye bekler. Bu bekleme event loop'u bloklamaz; diğer işler çalışmaya devam eder.
unref() ne işe yarar?
unref() edilmiş bir zamanlayıcı, süreci tek başına açık tutmaz. Başka bekleyen iş yoksa Node.js zamanlayıcının çalışmasını beklemeden kapanır. Periyodik arka plan işleri için kullanışlıdır.
Zamanlayıcı geri çağırması tam olarak ne zaman çalışır?
Belgeler kesin bir zaman vermez: geri çağırma, süre dolduktan sonra mümkün olan ilk anda çalışır. O sırada uzun süren senkron bir iş, yoğun bir poll fazı ya da işletim sisteminin zamanlaması onu geciktirebilir. Bu yüzden zamanlayıcıları ölçüm ya da saat olarak değil, "en erken şu kadar sonra" anlamında kullanın.
setInterval'i nasıl durdururum?
setInterval()'in döndürdüğü nesneyi bir değişkende saklayın ve clearInterval(nesne) çağırın. Promise sürümünde for await döngüsünden break ile çıkmanız ya da signal seçeneğine bağlı AbortController'ı iptal etmeniz yeterlidir.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Node.js öğrenme rehberi · nextTick ve setImmediate farkı · AbortController ve zaman aşımı · node:test mock ve coverage · JavaScript async/await