---
title: 'Hata Ayıklama Araçları'
source: 'https://academia.sh/tr/kurslar/eszamansiz-javascript/hata-ayiklama-araclari'
course: 'Eşzamansız JavaScript ve Çalışma Zamanı'
language: tr
updated: '2026-08-17T18:09:44+00:00'
license: 'CC BY-SA 4.0'
---

# Hata Ayıklama Araçları

Hata ayıklama arayüzüne bağlanma, kesme noktaları ve koşullu duraklar, gözlem ifadeleri, adımlama ve eşzamansız çağrı yığıtlarının okunması.

Profilleme nerede zaman harcandığını söyledi; neyin yanlış olduğunu söylemedi. Bunun için
programı belirli bir noktada durdurup değişkenlerine bakmak gerekir.

Bu ders tanı araçlarının ikinci yarısını ele alır. Örnekler ölçüm akışının aynı işleme
adımı üzerinde kurulacak; kullanılan düzenek, arayüz tabanlı araçların da altında çalışan
hata ayıklama arayüzüdür.

## Hata Ayıklama Arayüzü

Çalışma zamanı, kendisine bağlanan bir istemcinin programı durdurmasına, değişken
okumasına ve adım adım ilerletmesine izin veren bir arayüz sunar. Tarayıcı geliştirici
araçları, editör eklentileri ve komut satırı istemcileri aynı arayüzü kullanır.

Bağlanmanın üç yolu vardır. Çalışma zamanı ilgili seçenekle başlatılır ve bir istemci
bağlanır; başlangıçta duraklatan seçenekle başlatılır, böylece ilk satırdan itibaren
izlenir; ya da kodun içine `debugger` deyimi konur — bir istemci bağlıysa yürütme orada
durur.

Aşağıdaki örneklerde istemci yerine programın kendisi kullanılıyor: aynı arayüze program
içinden bağlanılıyor. Bu, arayüz tabanlı araçların hangi ilkelerle çalıştığını doğrudan
gösterir.

## Kesme Noktası, Koşul ve Gözlem İfadeleri

**Kesme noktası (breakpoint)**, yürütmenin durdurulacağı yerdir. Durak anında iki şey
incelenebilir: yerel değişkenlerin değerleri ve çağrı yığıtı.

Her durakta durmak, çok tekrarlı bir akışta işe yaramaz. **Koşullu kesme noktası**, yalnız
verilen ifade doğru olduğunda durur. Aşağıdaki program bunu, durak anında bir ifade
değerlendirip koşul sağlanmadığında hemen devam ederek gerçekleştirir.

```js
import { Session } from "node:inspector";

const oturum = new Session();
oturum.connect();
oturum.post("Debugger.enable");

function ifadeyiOku(cerceve, ifade) {
  let sonuc = null;
  oturum.post(
    "Debugger.evaluateOnCallFrame",
    { callFrameId: cerceve.callFrameId, expression: ifade },
    (hata, yanit) => {
      sonuc = yanit.result.value ?? yanit.result.description;
    },
  );
  return sonuc;
}

oturum.on("Debugger.paused", (olay) => {
  const cerceveler = olay.params.callFrames;
  const ust = cerceveler[0];
  const deger = ifadeyiOku(ust, "olcum.deger");

  if (deger > 20) {
    console.log("durak:", ust.functionName, "— satır", ust.location.lineNumber + 1);
    console.log("  gözlem: olcum.istasyon =", ifadeyiOku(ust, "olcum.istasyon"));
    console.log("  gözlem: olcum.deger =", deger);
    console.log("  yığıt:", cerceveler.slice(0, 3).map((c) => c.functionName).join(" <- "));
  }
  oturum.post("Debugger.resume");
});

function olcumIsle(olcum) {
  debugger;
  return { istasyon: olcum.istasyon, yuvarlanmis: Math.round(olcum.deger) };
}

function akisiIsle(olcumler) {
  return olcumler.map(function tekOlcumu(olcum) {
    return olcumIsle(olcum);
  });
}

const sonuc = akisiIsle([
  { istasyon: "A1", deger: 21.4 },
  { istasyon: "B2", deger: 19.8 },
  { istasyon: "C3", deger: 23.1 },
]);

console.log("sonuç:", sonuc.map((s) => `${s.istasyon}=${s.yuvarlanmis}`).join(" "));
oturum.disconnect();
```

```
durak: olcumIsle — satır 34
  gözlem: olcum.istasyon = A1
  gözlem: olcum.deger = 21.4
  yığıt: olcumIsle <- tekOlcumu <- akisiIsle
durak: olcumIsle — satır 34
  gözlem: olcum.istasyon = C3
  gözlem: olcum.deger = 23.1
  yığıt: olcumIsle <- tekOlcumu <- akisiIsle
sonuç: A1=21 B2=20 C3=23
```

Üç ölçümden ikisi koşulu sağladı ve bildirildi; ikinci ölçümde program hiç
duraklamamış gibi devam etti. Yazdırılan satır numarası, kaynak dosyadaki `debugger`
deyiminin bulunduğu satırdır; kod değişirse bu sayı da değişir.

**Gözlem ifadesi (watch expression)**, durak anında değerlendirilen ifadedir. Yalnız
değişken adı olmak zorunda değildir; `olcum.deger > 20` gibi bir ifade de, bir yöntem
çağrısı da değerlendirilebilir. Arayüz tabanlı araçlarda bu ifadeler bir listeye yazılır
ve her durakta yeniden hesaplanır.

Çağrı yığıtı görünümü de aynı durak verisinden gelir: `olcumIsle` çağrısına `tekOlcumu`
üzerinden, oraya da `akisiIsle` üzerinden gelinmiş. Bu zincir, "bu fonksiyon buraya nereden
çağrıldı" sorusunun yanıtıdır.

## Adımlama

Durakta üç ilerletme komutu vardır. **Üzerinden atlama (step over)** bir sonraki satıra
geçer; çağrılan fonksiyonların içine girmez. **İçine girme (step into)** çağrılan
fonksiyonun ilk satırında durur. **Dışına çıkma (step out)** içinde bulunulan fonksiyon
dönene kadar çalıştırır.

```js
import { Session } from "node:inspector";

const oturum = new Session();
oturum.connect();
oturum.post("Debugger.enable");

let adim = 0;

oturum.on("Debugger.paused", (olay) => {
  const ust = olay.params.callFrames[0];
  console.log("adım", adim, "— satır", ust.location.lineNumber + 1);
  adim += 1;
  if (adim < 8) oturum.post("Debugger.stepOver");
  else oturum.post("Debugger.resume");
});

function ortalamaAl(olcumler) {
  debugger;
  let toplam = 0;
  for (const olcum of olcumler) {
    toplam += olcum.deger;
  }
  const ortalama = toplam / olcumler.length;
  return ortalama;
}

const sonuc = ortalamaAl([
  { istasyon: "A1", deger: 21.4 },
  { istasyon: "B2", deger: 19.8 },
]);

console.log("ortalama:", sonuc.toFixed(2));
oturum.disconnect();
```

```
adım 0 — satır 18
adım 1 — satır 19
adım 2 — satır 20
adım 3 — satır 20
adım 4 — satır 21
adım 5 — satır 20
adım 6 — satır 21
adım 7 — satır 20
ortalama: 20.60
```

Satır dizisi döngünün yapısını açığa çıkarır: yirminci satır döngü başlığıdır ve her turda
iki kez görünür — bir kez yineleyiciden değer almak, bir kez turu bitirmek için. Yirmi
birinci satır gövdedir ve iki ölçüm için iki kez çalışır.

Adımlamanın eşzamansız kodda bir sınırı vardır: `await` ifadesinin üzerinden atlandığında
yürütme o fonksiyondan çıkar ve olay döngüsüne döner. Devamı, ilgili söz sonuçlandığında
başka bir turda çalışır. Bu nedenle eşzamansız akışlarda adımlama yerine, ilgilenilen
noktaya doğrudan kesme noktası koymak daha verimlidir.

## Eşzamansız Çağrı Yığıtı

Kursun ilk konusunda gösterildiği gibi, bir geri çağrı boş yığıtta çalışır. Bunun tanı
açısından sonucu ağırdır: geri çağrı içinde oluşan bir hatanın yığıtında, o işi *kim
başlattı* bilgisi yoktur.

Çalışma zamanları bu boşluğu eşzamansız çağrı yığıtlarıyla kapatır: `await` ile birbirine
bağlanan fonksiyonların zinciri korunur ve hata yığıtında `async` işaretiyle görünür.

```js
function cerceveleriYaz(hata) {
  const cerceveler = hata.stack
    .split("\n")
    .slice(1)
    .map((satir) => satir.trim())
    .filter((satir) => !satir.includes("node:"))
    .map((satir) => satir.replace(/\s*\(?file:.*$/, ""))
    .filter((satir) => satir !== "at async");
  for (const cerceve of cerceveler) console.log("  ", cerceve);
}

async function olcumGetir(istasyon) {
  await new Promise((karar) => setTimeout(karar, 5));
  throw new Error(`istasyon yanıt vermedi: ${istasyon}`);
}

async function olcumOku(istasyon) {
  return await olcumGetir(istasyon);
}

async function akisiIsle(istasyonlar) {
  const sonuclar = [];
  for (const istasyon of istasyonlar) {
    sonuclar.push(await olcumOku(istasyon));
  }
  return sonuclar;
}

function geriCagriylaGetir(istasyon, gericagri) {
  setTimeout(() => gericagri(new Error(`istasyon yanıt vermedi: ${istasyon}`)), 5);
}

try {
  await akisiIsle(["A1"]);
} catch (hata) {
  console.log("await zinciri —", hata.message);
  cerceveleriYaz(hata);
}

geriCagriylaGetir("B2", (hata) => {
  console.log("geri çağrı zinciri —", hata.message);
  cerceveleriYaz(hata);
});
```

```
await zinciri — istasyon yanıt vermedi: A1
   at olcumGetir
   at async olcumOku
   at async akisiIsle
geri çağrı zinciri — istasyon yanıt vermedi: B2
   at Timeout._onTimeout
```

Fark çarpıcıdır. `await` zincirinde hatanın yolu baştan sona görünüyor: hangi istasyon
okunurken, hangi akış işlenirken oluştuğu okunabiliyor. Geri çağrı zincirinde ise yalnız
zamanlayıcı çerçevesi var; isteği kimin başlattığı bilgisi kaybolmuş.

Çıktıdaki dosya yolları ve çalışma zamanına ait iç çerçeveler burada elenerek yazdırıldı;
gerçek bir yığıtta bunlar da bulunur ve makineye göre değişir. Arayüz tabanlı araçlar aynı
elemeyi "kütüphane kodunu gizle" biçiminde yapar.

Buradan çıkan tasarım kuralı, kursun geri çağrı dersindeki gerekçeye bir yenisini ekler:
sözlerle ve `await` ile yazılmış kod yalnız daha okunaklı değil, **daha tanılanabilirdir**.

## Yazdırarak Hata Ayıklama

Konsola yazdırmak ilkel görünse de bazı durumlarda tek uygulanabilir yöntemdir: sorun
seyrek ortaya çıkıyorsa, üretim ortamındaysa ya da durdurmanın kendisi davranışı
değiştiriyorsa.

İki iyileştirme onu ciddi bir araç haline getirir. Birincisi, kayıtların **bağlam
taşımasıdır**: hangi istasyon, hangi deneme, hangi işlem anahtarı. Bağlamsız bir "buraya
geldi" satırı, eşzamansız bir akışta hangi isteğe ait olduğunu söylemez.

İkincisi, **kayıt noktası (logpoint)** kullanmaktır: kesme noktası gibi kurulur, ama
durdurmak yerine bir ifade yazdırıp devam eder. Böylece kod değiştirilmeden ve yeniden
başlatılmadan gözlem eklenebilir.

## Özet

- Hata ayıklama arayüzü, programı durdurma, değişken okuma ve adım adım ilerletme
  işlemlerini sunar; arayüz tabanlı araçlar da bu arayüzü kullanır.
- Kesme noktası bir koşula bağlanabilir; gözlem ifadeleri durak anında değerlendirilir ve
  çağrı yığıtı çağrının nereden geldiğini gösterir.
- Adımlama komutları üzerinden atlama, içine girme ve dışına çıkma biçimindedir; `await`
  üzerinden atlandığında yürütme olay döngüsüne döner.
- Eşzamansız çağrı yığıtı, `await` ile bağlanan zinciri korur; geri çağrı tabanlı kodda
  bu zincir kaybolur.
- Yazdırarak hata ayıklama, kayıtlar bağlam taşıdığında ve kayıt noktaları kullanıldığında
  ciddi bir araçtır.

## Kurs Kapanışı

Kurs tek bir soruyla başladı: tek iş parçacıklı bir dil, beklemeyi nasıl karşılar? Yanıt
adım adım kuruldu.

Önce **model** kuruldu: kullanıcı kodu tek iş parçacığında, sonuna kadar çalışarak yürür;
olay döngüsü her turda görev kuyruğundan bir iş alır ve ardından mikro görev kuyruğunu
tamamen boşaltır. Bu kural, kurstaki her çıktı sırasının gerekçesiydi.

Sonra **soyutlama** kuruldu: geri çağrının bıraktığı boşluk — birleştirilememe, hata
yolunun elle taşınması, sözleşme ihlalleri — sözün durum makinesiyle kapandı.
Birleştiriciler beklemenin yapısını verdi, `async` ve `await` ise okunuşu düzeltti;
ikisi de sözün üzerine oturan katmanlardı, yeni bir eşzamansızlık düzeneği değil.

Ardından **denetim** kuruldu: iptal işareti, zaman aşımı ve yeniden deneme kalıpları.
Buradaki ayrım kursun en pratik dersidir — beklemeyi kesmek işi kesmez.

Son olarak **gözlem** kuruldu: erişilebilirlik temelli bellek modeli, anlık görüntü
karşılaştırmasıyla sızıntı tanısı, ana iş parçacığı profillemesi ve kesme noktalarıyla
durum incelemesi. Ölçüm akışı örneği, tek bir zamanlayıcı geri çağrısından başlayıp
iptal edilebilir, zaman aşımlı, dayanıklı ve sızıntı bırakmayan bir akışa dönüştü.

Kalan konu, bu kodun nasıl paketlendiği ve dağıtıldığıdır. Sonraki kurs — Modüller,
Araçlar ve Ekosistem — modül sistemlerini, paketlerin çözümlenme biçimini, bağımlılık
sürümlemesini ve derleme araçlarını ele alır. Bu kursta birkaç kez modül biçimine
değinilmiş ve ayrıntısı oraya bırakılmıştı; sıra oraya geldi.
