---
title: 'Kalıcı Durum'
source: 'https://academia.sh/tr/kurslar/frontend-mimarisi/kalici-durum'
course: 'Uygulama Mimarisi: Yönlendirme, Durum ve Veri'
language: tr
updated: '2026-08-17T18:09:21+00:00'
license: 'CC BY-SA 4.0'
---

# Kalıcı Durum

Durumun depolamaya yazılması; hangi dilimin kalıcılaştırılacağı, dilim başına sürümleme ve göç zinciri, varsayılanlarla birleştirme, yazma maliyetinin seyreltilmesi, iki sekmenin çakışması ve başlangıç durumunun kurulması.

Durumun nereye konacağı ve nasıl güncelleneceği çözüldü, ama tümü bellekte duruyor. Kuzey
Yamaç Ölçüm İstasyonu uygulamasında kullanıcı sekmeyi kapattığında arayüz teması, seçili
birim sistemi ve son görüntülenen istasyonlar kayboluyor.

Tarayıcı ve Web Platformu kursundaki Depolama API'leri dersi saklama yerini kurdu:
katmanların ömürleri, dizgi deposunun tip kayıpları, kota ve şema göçü. Bu ders o yerin
üzerine durum katmanını oturtur ve dört ayrı soruyu yanıtlar: hangi dilim yazılır, kayıt
kod değişince nasıl okunur, ne zaman yazılır, iki sekme aynı anda yazarsa ne olur.

## Hangi Dilim Kalıcılaştırılır

Ölçüt iki koşulun birleşimidir: değer **yeniden üretilemiyorsa** ve kullanıcı kaybını
**fark edecekse** kalıcılaştırılır. Arayüz teması ikisini de karşılar; kullanıcı onu bir kez
seçmiştir ve her açılışta yeniden seçmek istemez.

Dört tür dışarıda kalır. **Sunucu durumu** kalıcılaştırılmaz — kaynağı uzaktadır ve
kopyanın tazeliği zaten ayrı bir katmanın işidir; bir sonraki açılışta gösterilecek eski
veri, tazelik penceresi olmadan yanlış veridir. **URL durumu** kalıcılaştırılmaz; zaten
adreste taşınır ve iki yere yazılırsa hangisinin kazanacağı belirsizleşir. **Türetilmiş
değer** kalıcılaştırılmaz; girdileri saklanır. **Kimlik belirteci ve kişisel veri** de
kalıcılaştırılmaz; Depolama API'leri dersinde kurulan kural gereği sayfada çalışan her kod
o depoyu okuyabilir.

Geriye paylaşılan istemci durumunun bir bölümü ile kullanıcının yarım bıraktığı girişler
kalır.

## Dilim Başına Sürüm

Depolanan veri onu yazan koddan uzun yaşar. Depolama API'leri dersi bunun çözümünü kurmuştu:
kayıt bir sürüm alanı taşır, okuma yolu eski sürümü güncele taşıyan bir göç zincirinden
geçer.

Durum katmanında bir ekleme gerekir. Tek bir sürüm numarası tüm kaydı kapsarsa, tek bir
dilimin biçimi değiştiğinde bütün kaydın sürümü artar ve her dilim için bir göç adımı
yazılmak zorunda kalınır. Dilimler birbirinden bağımsız geliştiği için sürüm de **dilim
başına** tutulur.

```js
// kalici-durum.mjs — dilim basina surumleme, goc zinciri ve sekmeler arasi birlestirme
const SEMA = {
  tercihler: {
    surum: 3,
    varsayilan: { tema: "acik", birim: "metrik", satirYuksekligi: "normal" },
    goc: {
      1: (d) => ({ ...d, birim: "metrik" }),                       // 1 -> 2: birim eklendi
      2: ({ koyuTema, ...d }) => ({ ...d, tema: koyuTema ? "koyu" : "acik" }),  // 2 -> 3
    },
  },
  sonGorulenler: { surum: 1, varsayilan: [], goc: {} },
};

function kalicilastir(durum) {                    // yalniz semada yazili dilimler yazilir
  const kayit = {};
  for (const [ad, k] of Object.entries(SEMA)) kayit[ad] = { surum: k.surum, veri: durum[ad] };
  return JSON.stringify(kayit);
}

function geriYukle(ham) {
  const not = [];
  let kayit;
  try { kayit = JSON.parse(ham); } catch { return { durum: varsayilanlar(), not: ["cozumlenemedi"] }; }

  const durum = {};
  for (const [ad, k] of Object.entries(SEMA)) {
    const dilim = kayit[ad];
    if (!dilim || typeof dilim.surum !== "number") { durum[ad] = k.varsayilan; not.push(`${ad}: yok`); continue; }
    if (dilim.surum > k.surum) { durum[ad] = k.varsayilan; not.push(`${ad}: gelecek surum`); continue; }
    let veri = dilim.veri, s = dilim.surum;
    while (s < k.surum) { veri = k.goc[s](veri); s += 1; }
    if (s !== dilim.surum) not.push(`${ad}: ${dilim.surum} -> ${k.surum}`);
    durum[ad] = Array.isArray(k.varsayilan) ? veri : { ...k.varsayilan, ...veri };
  }
  for (const ad of Object.keys(kayit))
    if (!(ad in SEMA)) not.push(`${ad}: semada yok, atildi`);
  return { durum, not };
}

const varsayilanlar = () =>
  Object.fromEntries(Object.entries(SEMA).map(([ad, k]) => [ad, k.varsayilan]));

console.log("-- geri yukleme --");
const ORNEKLER = [
  ['{"tercihler":{"surum":3,"veri":{"tema":"koyu","birim":"metrik","satirYuksekligi":"sik"}},"sonGorulenler":{"surum":1,"veri":["kuzey-yamac"]}}', "guncel kayit"],
  ['{"tercihler":{"surum":1,"veri":{"koyuTema":true}},"sonGorulenler":{"surum":1,"veri":[]}}', "iki surum eski"],
  ['{"tercihler":{"surum":3,"veri":{"tema":"koyu"}}}', "eksik dilim + eksik alan"],
  ['{"tercihler":{"surum":9,"veri":{}},"sonGorulenler":{"surum":1,"veri":["dogu-sirt"]}}', "gelecek surum"],
  ['{"tercihler":{"surum":3,"veri":{}},"oturum":{"surum":1,"veri":{"belirtec":"abc"}}}', "artik yazilmayan dilim"],
  ['{tercihler:}', "bozuk icerik"],
];
for (const [ham, etiket] of ORNEKLER) {
  const { durum, not } = geriYukle(ham);
  console.log(etiket.padEnd(26), JSON.stringify(durum));
  console.log(" ".repeat(26), "not:", not.join("; ") || "-");
}

console.log("-- iki sekme --");
const A = { tercihler: { tema: "koyu", birim: "metrik", satirYuksekligi: "normal" }, sonGorulenler: ["kuzey-yamac"] };
const B = { tercihler: { tema: "acik", birim: "metrik", satirYuksekligi: "normal" }, sonGorulenler: ["dogu-sirt", "bati-vadi"] };

// Tumunu yazma: son yazan digerinin dilimini de ezer.
console.log("A yazdi           ", kalicilastir(A));
console.log("B yazdi (tumu)    ", kalicilastir(B));

// Dilim basina yazma: her sekme yalniz degistirdigi dilimi yazar.
function dilimYaz(ham, ad, veri) {
  const kayit = JSON.parse(ham);
  kayit[ad] = { surum: SEMA[ad].surum, veri };
  return JSON.stringify(kayit);
}
const sonrasi = dilimYaz(kalicilastir(A), "sonGorulenler", B.sonGorulenler);
console.log("B yazdi (dilim)   ", sonrasi);
console.log("A'nin temasi durdu:", geriYukle(sonrasi).durum.tercihler.tema);
```

```
-- geri yukleme --
guncel kayit               {"tercihler":{"tema":"koyu","birim":"metrik","satirYuksekligi":"sik"},"sonGorulenler":["kuzey-yamac"]}
                           not: -
iki surum eski             {"tercihler":{"tema":"koyu","birim":"metrik","satirYuksekligi":"normal"},"sonGorulenler":[]}
                           not: tercihler: 1 -> 3
eksik dilim + eksik alan   {"tercihler":{"tema":"koyu","birim":"metrik","satirYuksekligi":"normal"},"sonGorulenler":[]}
                           not: sonGorulenler: yok
gelecek surum              {"tercihler":{"tema":"acik","birim":"metrik","satirYuksekligi":"normal"},"sonGorulenler":["dogu-sirt"]}
                           not: tercihler: gelecek surum
artik yazilmayan dilim     {"tercihler":{"tema":"acik","birim":"metrik","satirYuksekligi":"normal"},"sonGorulenler":[]}
                           not: sonGorulenler: yok; oturum: semada yok, atildi
bozuk icerik               {"tercihler":{"tema":"acik","birim":"metrik","satirYuksekligi":"normal"},"sonGorulenler":[]}
                           not: cozumlenemedi
-- iki sekme --
A yazdi            {"tercihler":{"surum":3,"veri":{"tema":"koyu","birim":"metrik","satirYuksekligi":"normal"}},"sonGorulenler":{"surum":1,"veri":["kuzey-yamac"]}}
B yazdi (tumu)     {"tercihler":{"surum":3,"veri":{"tema":"acik","birim":"metrik","satirYuksekligi":"normal"}},"sonGorulenler":{"surum":1,"veri":["dogu-sirt","bati-vadi"]}}
B yazdi (dilim)    {"tercihler":{"surum":3,"veri":{"tema":"koyu","birim":"metrik","satirYuksekligi":"normal"}},"sonGorulenler":{"surum":1,"veri":["dogu-sirt","bati-vadi"]}}
A'nin temasi durdu: koyu
```

Göç zinciri ikinci satırda iki adım çalışmıştır. En eski biçimde tema bir mantıksal alanla
tutuluyordu; iki geçişte önce birim eklenmiş, sonra alan yeniden adlandırılıp değeri
dönüştürülmüştür. Dilimin sürümü kendi başına ilerlediği için diğer dilime hiç
dokunulmamıştır.

## Okuma Sınırı

Kalan satırlar okuma tarafının savunmasını gösterir ve hepsi aynı ilkeden çıkar: depodan
gelen her şey dış girdidir.

Eksik dilim varsayılanına düşer. **Eksik alan** da varsayılanla tamamlanır; üçüncü satırda
yalnız tema yazılmış olmasına karşın birim ve satır yüksekliği varsayılan değerlerini
almıştır. Bu birleştirme, yeni bir alan eklendiğinde eski kayıtların geçersiz sayılmasını
önler; alan eklemek göç adımı gerektirmez.

Gelecek sürümlü dilim geriye taşınamayacağı için varsayılana düşer — kullanıcı başka bir
cihazda daha yeni bir sürüm kullanmış olabilir. Çözümlenemeyen içerikte tüm kayıt
bırakılır. Şemada bulunmayan dilim ise atılır; bu, artık kalıcılaştırılmayan eski bir
alanın — örnekte bir oturum belirtecinin — depoda kalmaya devam etmesini önler.

Son durum ayrıca bir temizlik görevidir. Bir dilim kalıcılaştırma listesinden çıkarıldığında
depodaki eski kaydın da silinmesi gerekir; yalnız yazmayı durdurmak, orada duran veriyi
ortadan kaldırmaz.

## Yazma Zamanı

Depolama API'leri dersi ilk iki katmanın erişiminin eşzamanlı olduğunu ve büyük kayıtların
ana iş parçacığını bekletebileceğini kurmuştu. Durum katmanı her değişimde yazmaya adaydır;
bu, her tuş vuruşunda depoya yazan bir kod anlamına gelebilir.

Üç kural maliyeti sınırlar. Yazma **seyreltilir**: değişimden sonra kısa bir sessizlik
beklenir ve tek bir yazma yapılır. Yalnız **değişen dilim** yazılır; tercihler değişmediyse
o dilime dokunulmaz. Ve kayıt **küçük tutulur**; büyüyen veri eşzamansız arayüzlü
yapılandırılmış depolamaya taşınır.

Sekme kapanırken son bir yazma yapılmak istenebilir. Sayfanın kapanış anında güvenilir
biçimde çalışan tek yol eşzamanlı bir yazmadır ve o anda uzun bir işlem tamamlanmayabilir;
bu nedenle kapanışa güvenmek yerine değişim anında yazmak tercih edilir.

## İki Sekme

Son bölüm bir kayıp senaryosunu gösterir. Aynı kaynağın iki sekmesi aynı depoyu paylaşır.
Birinci sekmede tema koyuya çevrilmiş, ikinci sekmede son görüntülenenler değişmiştir.

İkinci sekme **tüm kaydı** yazdığında birinci sekmenin teması geri açığa döner: ikinci
sekmenin bellekteki kopyası, tema değişikliğinden önceki hâldir. Yalnız **değiştirdiği
dilimi** yazdığında ise iki değişiklik de korunur; çıktının son satırı bunu doğrular.

Dilim başına yazma çakışmayı daraltır, ortadan kaldırmaz: aynı dilimi iki sekme birden
değiştirdiğinde son yazan kazanır. Bunun kabul edilebilir olduğu yerlerde başka bir şey
yapılmaz. Kabul edilemediği yerlerde, Depolama API'leri dersinde tanıtılan depolama olayı
dinlenir ve diğer sekmedeki değişiklik belleğe alınır; böylece bir sonraki yazma güncel
kayıt üzerine yapılır.

## Başlangıç Durumunun Kurulması

Uygulama açılırken depodan okunan durum, bellekteki durumun başlangıç değeri olur. Sıra
önemlidir: okuma **ilk çizimden önce** yapılırsa ekran doğru temayla açılır. Sonra
yapılırsa uygulama önce varsayılan temayla çizilir, ardından kayıtlı temaya geçer ve
kullanıcı bir sıçrama görür.

Eşzamansız bir depolama katmanı kullanıldığında bu sıçrama kaçınılmaz görünür. İki çözüm
vardır: sıçramaya yol açan küçük tercihleri eşzamanlı katmanda tutmak, ya da ilk çizimi
kayıt okunana kadar geciktirmek. İkinci çözüm boş ekran süresini uzattığı için genellikle
yalnız ilk çözümün yetmediği yerlerde seçilir.

## Özet

- Yeniden üretilemeyen ve kaybı kullanıcı tarafından fark edilecek istemci durumu
  kalıcılaştırılır; sunucu durumu, URL durumu, türetilmiş değer ve kimlik belirteci
  kalıcılaştırılmaz.
- Sürüm dilim başına tutulur; bir dilimin biçim değişikliği diğer dilimler için göç adımı
  yazmayı gerektirmez.
- Okuma tarafı savunmalıdır: eksik dilim ve eksik alan varsayılanla tamamlanır, gelecek
  sürümlü ve çözümlenemeyen içerik yok sayılır, şemada bulunmayan dilim atılır ve silinir.
- Alan eklemek göç adımı gerektirmez, çünkü okuma varsayılanlarla birleştirir; alan
  yeniden adlandırmak veya tipini değiştirmek gerektirir.
- Yazma seyreltilir, yalnız değişen dilim yazılır ve kayıt küçük tutulur; kapanış anındaki
  yazmaya güvenilmez.
- İki sekme tüm kaydı yazdığında birbirinin dilimini ezer; dilim başına yazma bunu önler,
  aynı dilimdeki çakışma için depolama olayı dinlenir.

## Sonraki Adım

Durumun nerede tutulacağı, nasıl güncelleneceği ve nasıl kalıcılaştığı çözüldü. Bir
katmanın içi ise hâlâ boş: sunucu durumu önbelleği "isteği yap, yanıtı yaz" diyor ama
isteğin nasıl yapıldığını, yanıtın hangi biçimde beklendiğini ve hatanın nasıl temsil
edileceğini söylemiyor. Bir istek başarısız olduğunda katmanın eline ne geçer — bir durum
kodu mu, bir hata gövdesi mi, bir ağ kesintisi mi? Bu üçü aynı biçimde ele alınamaz.
Sonraki konu veri erişimini ele alır ve ilk dersi olan REST İstemcisi, istek katmanının
tasarımını ve uygulamanın her yerinde geçerli olacak hata sözleşmesini kurar.
