---
title: 'Geçmiş ve Konum'
source: 'https://academia.sh/tr/kurslar/tarayici-platformu/gecmis-ve-konum'
course: 'Tarayıcı ve Web Platformu'
language: tr
updated: '2026-08-17T18:09:10+00:00'
license: 'CC BY-SA 4.0'
---

# Geçmiş ve Konum

Sayfa durumunun adrese yazılması ve geçmiş yığıtının programla yönetilmesi; adresin parçaları, hangi durumun yola sorguya ya da parçaya ait olduğu, ekleme ile değiştirme ayrımı, gezinme olayı ve sunucu tarafının payı.

Önceki ders durumu sakladı ama durumun adresle ilişkisine dokunmadı. Süzgeç ölçütü depoda
tutulduğunda sayfa yeniden açıldığında geri gelir; ancak o hâlin bir adresi yoktur.
Kullanıcı süzülmüş listeyi paylaşamaz, yer imine ekleyemez, geri düğmesiyle önceki süzgece
dönemez.

Bunlar depolamanın değil **gezinmenin** sorunlarıdır. Tarayıcının adres çubuğu ve geçmiş
yığıtı, sayfa yeniden yüklenmeden de değiştirilebilir. Bu ders adresin parçalarını,
yığıtın nasıl yönetildiğini ve istemci tarafı gezinmenin sunucudan ne istediğini kurar.

## Adresin Parçaları

Web'in Temelleri ve HTML kursundaki Bağlantılar dersinde adres bir dizgi olarak
tanıtılmıştı. Program tarafında adres, parçalarına ayrılmış bir nesnedir ve her parça ayrı
ayrı okunup yazılabilir.

```js
// adres.mjs — adresin parcalari ve sorgu dizgisinin duzenlenmesi
const adres = new URL("https://ornek.gecerli/istasyon/kuzey-yamac/gunluk?olcum=sicaklik&esik=-5&sayfa=3#ozet");

for (const alan of ["protocol", "host", "pathname", "search", "hash"])
  console.log(alan.padEnd(9), JSON.stringify(adres[alan]));

// Suzgec degistiginde yalniz ilgili parametreler yazilir, digerleri korunur.
const yeni = new URL(adres);
yeni.searchParams.set("olcum", "bagil nem");
yeni.searchParams.delete("sayfa");            // suzgec degisince sayfalama basa doner
console.log("yeni      ", yeni.pathname + yeni.search + yeni.hash);

// Ayni ada birden cok deger baglanabilir; okuma iki ayri islemle yapilir.
yeni.searchParams.append("etiket", "gece");
yeni.searchParams.append("etiket", "kar");
console.log("etiket tek", JSON.stringify(yeni.searchParams.get("etiket")));
console.log("etiket cok", JSON.stringify(yeni.searchParams.getAll("etiket")));

// Goreli adres, taban adrese gore cozumlenir.
console.log("goreli    ", new URL("../ozet?olcum=sicaklik", adres).href);
```

```
protocol  "https:"
host      "ornek.gecerli"
pathname  "/istasyon/kuzey-yamac/gunluk"
search    "?olcum=sicaklik&esik=-5&sayfa=3"
hash      "#ozet"
yeni       /istasyon/kuzey-yamac/gunluk?olcum=bagil+nem&esik=-5#ozet
etiket tek "gece"
etiket cok ["gece","kar"]
goreli     https://ornek.gecerli/istasyon/ozet?olcum=sicaklik
```

Sorgu dizgisini elle birleştirmek yerine sağlanan arayüzle düzenlemenin üç kazancı çıktıda
görünür. Kaçırma kendiliğinden yapılır: boşluk içeren değer kodlanmıştır. İlgisiz
parametreler korunur; süzgeç değişirken eşik değeri yerinde kalmıştır. Aynı ada bağlı
birden çok değer desteklenir ve tek değer okuma ile tüm değerleri okuma ayrı işlemlerdir.

Sayfalama parametresinin silinmesi kod değil karar örneğidir: süzgeç değiştiğinde eski
sayfa numarası anlamını yitirir. Adres durumu taşıdığı için, durumlar arası bu tür
bağımlılıklar da adres üzerinde işletilir.

## Hangi Durum Adrese Yazılır

Adresin her parçası farklı bir soruya karşılık gelir.

**Yol (path)** kaynağın kimliğidir: hangi istasyonun günlüğü görüntüleniyor. Kaynak
değişiyorsa yol değişir.

**Sorgu (query string)** aynı kaynağın hangi görünümünün istendiğini söyler: süzgeç,
sıralama, sayfa numarası. Ölçüm listesinin süzülmüş hâli buraya yazılır ve böylece
paylaşılabilir olur.

**Parça (fragment)** belge içindeki konumu gösterir ve sunucuya hiç gönderilmez. Sayfa
içi bağlantılar ve sunucunun bilmesi gerekmeyen geçici görünüm ayarları buraya uygundur.

Adrese **yazılmaması gereken** durum da vardır: bir düğmenin üzerine gelinmesi, bir
animasyonun ilerlemesi, açık bir ipucu balonu. Ölçüt şudur: kullanıcı bu adresi yeni bir
sekmede açtığında aynı ekranı görmeyi bekliyor mu. Yanıt hayırsa durum adrese girmez.

Bir de gizlilik ölçütü vardır. Adres kütüklere yazılır, yönlendirenler üzerinden dış
sunuculara gidebilir ve kullanıcı tarafından paylaşılır; kişisel veri ve belirteç adrese
konmaz.

## Geçmiş Yığıtı

Tarayıcının geçmişi bir yığıt değil, üzerinde ileri geri hareket edilen bir kayıt dizisidir.
Program bu diziyi üç işlemle etkiler.

```js
// gecmis.mjs — gecmis yiginin uc islemi ve hangisinin olay urettigi
class Gecmis {
  constructor(ilk) { this.girisler = [ilk]; this.dizin = 0; }
  get simdi() { return this.girisler[this.dizin]; }
  ekle(giris) {                       // ileri kayitlar atilir
    this.girisler.length = this.dizin + 1;
    this.girisler.push(giris);
    this.dizin += 1;
    return null;                      // olay uretilmez
  }
  degistir(giris) {
    this.girisler[this.dizin] = giris;
    return null;                      // olay uretilmez
  }
  git(adim) {
    const hedef = this.dizin + adim;
    if (hedef < 0 || hedef >= this.girisler.length) return "sinir disi, is yapilmadi";
    this.dizin = hedef;
    return this.simdi.durum;          // olay uretilir, durum nesnesi tasinir
  }
}

const g = new Gecmis({ ad: "liste", durum: { olcum: "hepsi" } });
const yaz = (islem, olay) =>
  console.log(
    islem.padEnd(16),
    "dizin:", g.dizin,
    "| yigin:", g.girisler.map((x) => x.ad).join(" "),
    "| olay:", olay === null ? "yok" : JSON.stringify(olay),
  );

yaz("baslangic", null);
yaz("ekle(sicaklik)", g.ekle({ ad: "sicaklik", durum: { olcum: "sicaklik" } }));
yaz("ekle(nem)", g.ekle({ ad: "nem", durum: { olcum: "nem" } }));
yaz("degistir(nem*)", g.degistir({ ad: "nem*", durum: { olcum: "nem", sayfa: 2 } }));
yaz("git(-1)", g.git(-1));
yaz("git(-1)", g.git(-1));
yaz("git(-1)", g.git(-1));
yaz("ekle(ruzgar)", g.ekle({ ad: "ruzgar", durum: { olcum: "ruzgar" } }));
yaz("git(+1)", g.git(1));
```

```
baslangic        dizin: 0 | yigin: liste | olay: yok
ekle(sicaklik)   dizin: 1 | yigin: liste sicaklik | olay: yok
ekle(nem)        dizin: 2 | yigin: liste sicaklik nem | olay: yok
degistir(nem*)   dizin: 2 | yigin: liste sicaklik nem* | olay: yok
git(-1)          dizin: 1 | yigin: liste sicaklik nem* | olay: {"olcum":"sicaklik"}
git(-1)          dizin: 0 | yigin: liste sicaklik nem* | olay: {"olcum":"hepsi"}
git(-1)          dizin: 0 | yigin: liste sicaklik nem* | olay: "sinir disi, is yapilmadi"
ekle(ruzgar)     dizin: 1 | yigin: liste ruzgar | olay: yok
git(+1)          dizin: 1 | yigin: liste ruzgar | olay: "sinir disi, is yapilmadi"
```

Dört kural bu çıktıda okunur.

**Ekleme yeni bir kayıt açar ve ileri kayıtları atar.** Son satırlarda geri gidildikten
sonra yapılan ekleme, ileri yöndeki iki kaydı silmiştir; ileri düğmesi artık çalışmaz. Bu,
tarayıcının kendi gezinmesinde de aynıdır.

**Değiştirme kayıt sayısını artırmaz.** Süzgeç alanına yazılan her karakter için ekleme
yapan bir sayfa, kullanıcının geri düğmesini kullanılamaz hâle getirir: her basış bir harf
geri alır. Kullanıcının geri dönmek isteyeceği durumlar eklenir, ara durumlar değiştirilir.

**Olay yalnızca dolaşımda üretilir.** Ekleme ve değiştirme olay üretmez; bunları yapan kod
arayüzü kendisi günceller. Bu, önceki derste yerel depolama olayının yazan sekmede
üretilmemesiyle aynı tasarımdır.

**Her kaydın kendi durum nesnesi vardır.** Olay bu nesneyi taşır; sayfa geri gidildiğinde
hangi görünümün kurulacağı buradan okunur. Durum nesnesi serileştirilerek saklandığı için
Depolama API'leri dersindeki sınır burada da geçerlidir: işlev, düğüm ve devingen nesne
konamaz, boyutu gerçekleştirime bağlı bir sınırla kısıtlıdır. Sağlam yol, durum nesnesine
yalnızca adresten türetilemeyen küçük bilgileri koymaktır — kaydırma konumu, açık panelin
kimliği gibi.

Modelin bir noktası tarayıcıdan ayrılır: burada sınırın dışına çıkan hareket iş yapmadan
döner. Tarayıcıda geçmiş sekmeye aittir ve sayfadan önceki kayıtları da içerir; ilk kaydın
gerisine gitmek siteden çıkar. Kod bu nedenle "geri gidilecek kayıt var mı" varsayımı
kuramaz.

## Sunucu Tarafının Payı

İstemci tarafı gezinme adresi sayfa yeniden yüklenmeden değiştirir. Bunun bir koşulu
vardır ve unutulduğunda hata yalnızca ikinci ziyarette görünür: **kullanıcı o adresi
doğrudan açtığında sunucu geçerli bir yanıt vermelidir.**

Adres çubuğunda süzülmüş listenin adresi görünüyorsa, kullanıcı o adresi kopyalayıp yeni
bir sekmede açabilir, yer imine ekleyebilir, arama sonucundan gelebilir. Bu isteklerde
tarayıcı yeni bir belge ister. Sunucu o yolu tanımıyorsa yanıt bulunamadı olur. İnternet
Nasıl Çalışır kursunda tanımlanan durum kodları burada doğrudan kullanıcıya yansır.

İki çözüm sınıfı vardır. Sunucu her yol için gerçek bir belge üretir; ya da tanımlı yol
örüntülerini tek bir belgeye eşler ve görünümü istemci kurar. İkinci yolda dikkat edilecek
nokta, gerçekten bulunmayan adreslerin yine de bulunamadı yanıtı almasıdır; her adrese
başarılı yanıt veren bir sunucu, arama motorlarına ve bağlantı denetleyicilerine yanlış
bilgi verir.

Konum nesnesine yazmak ayrı bir işlemdir ve **her zaman gerçek gezinme başlatır**. Bu
gezinmenin geçmişe kayıt ekleyen ve o anki kaydın yerine geçen iki biçimi vardır;
ikincisi, kullanıcının geri döndüğünde yeniden yönlendirileceği ara adresler için
kullanılır.

## Gezinme Sırasında İki Sorumluluk

Sayfa yeniden yüklenmeden yapılan gezinme, tarayıcının kendiliğinden yaptığı iki işi de
devralır.

Birincisi **kaydırma konumudur**. Gerçek gezinmede tarayıcı, geri dönülen sayfanın
kaydırma konumunu geri yükler. Belge yerinde kalıp yalnızca içeriği değişen bir sayfada
bu davranış yanlış zamanda çalışabilir: yeni içerik henüz yerleşmemişken eski konuma
gidilir. Tarayıcı bu nedenle geri yüklemeyi elle üstlenmeye izin veren bir ayar sunar;
sayfa konumu kendi durum nesnesinde saklar ve içerik yerleştikten sonra uygular.

İkincisi **iptal edilmeyen isteklerdir**. Yeni görünüm için veri istendiğinde kullanıcı
beklemeden başka bir bağlantıya geçebilir. Eski isteğin yanıtı sonra gelirse, ekranda
duran görünümün üstüne eski veri yazılır. Eşzamansız JavaScript ve Çalışma Zamanı
kursundaki İptal ve Zaman Aşımı dersinde tanımlanan iptal işareti bu yarışın çözümüdür:
her gezinme kendi işaretini açar, sonraki gezinme öncekini iptal eder. İptal edilmemiş
isteklerin yanıtı, geldiğinde hangi gezinmeye ait olduğu sınanarak yok sayılır.

## Özet

- Adres parçalara ayrılmış bir nesnedir; sorgu dizgisi sağlanan arayüzle düzenlendiğinde
  kaçırma kendiliğinden yapılır ve ilgisiz parametreler korunur.
- Yol kaynağın kimliğini, sorgu aynı kaynağın görünümünü, parça belge içindeki konumu
  taşır; paylaşıldığında yeniden kurulması beklenmeyen durum adrese yazılmaz.
- Geçmişe ekleme ileri kayıtları atar; ara durumlar için o anki kaydı değiştirmek
  kullanıcının geri düğmesini korur.
- Gezinme olayı yalnızca geçmişte dolaşıldığında üretilir; ekleme ve değiştirme yapan kod
  arayüzü kendisi günceller.
- Her geçmiş kaydının serileştirilebilir bir durum nesnesi vardır; boyutu sınırlıdır ve
  adresten türetilebilen bilgi oraya konmaz.
- İstemci tarafı gezinmenin ürettiği her adres doğrudan istendiğinde sunucudan geçerli bir
  yanıt almalı, bulunmayan adresler yine bulunamadı yanıtı vermelidir; kaydırma konumunun
  geri yüklenmesi ve eski isteklerin iptali de sayfanın sorumluluğuna geçer.

## Sonraki Adım

Adres ve geçmiş, kullanıcının **istediği** görünümü tanımlar. Ancak görünümün ekranda ne
kadarının göründüğü, kabın ne kadar genişlediği ve ağacın ne zaman değiştiği bu bilgiden
okunamaz. Uzun ölçüm listesinde görsellerin yalnızca yaklaştıklarında yüklenmesi, bir
grafiğin kabı daraldığında yeniden çizilmesi, sonradan eklenen satırların bir kütüğe
işlenmesi — üçü de sürekli ölçüm yapmayı gerektirir. Bunu her karede elle yapmak hem
pahalıdır hem de ölçümün kendisi yerleşimi zorlar. Sonraki ders, tarayıcının bu üç soruyu
toplu ve eşzamansız biçimde yanıtlayan gözlemci ailesini ele alır.
