İçeriğe geç
academia.sh

Ders 01 / 20

Tarayıcı ile Farklar

Barındıran ortam kavramı, genel nesnenin içeriği, iki modül sisteminin bir arada bulunması ve sunucu çalışma zamanının yetenek sınırları.

İçindekiler

Eşzamansız JavaScript ve Çalışma Zamanı kursu, tek iş parçacıklı yürütme modelini ve olay döngüsünü kurdu. Orada anlatılan her şey dilin kendisine değil, dili barındıran ortama aitti: görev kuyruğu da, zamanlayıcılar da dil standardında tanımlı değildir. Bu kurs aynı dili farklı bir barındıran ortamda ele alır.

Soru şudur: aynı sözdizim, aynı değer modeli ve aynı olay döngüsü kavramı, tarayıcı yerine bir sunucu sürecinde çalıştığında ne değişir? Yanıt iki başlıkta toplanır — hangi adların hazır bulunduğu ve sürecin ne yapmaya yetkili olduğu.

Dil Çekirdeği ve Barındıran Ortam

Dil standardı, sözdizimi ve değer modelini tanımlar: Array, Map, Promise, JSON, Math bu katmandadır. Standart, bu değerlerin nasıl davranacağını söyler; onlarla dış dünyaya nasıl erişileceğini söylemez.

Barındıran ortam (host environment), dili çalıştıran programdır ve dış dünyayla teması o sağlar. Tarayıcı bir barındıran ortamdır: belge ağacını, çerezleri, ekran olaylarını sunar. Sunucu çalışma zamanı da bir barındıran ortamdır: dosya sistemini, süreç bilgisini, ağ dinlemeyi sunar.

Ayrım şöyle sınanabilir. Aşağıdaki dosya, bir dizi adın genel nesnede bulunup bulunmadığını yazar:

// ortam.mjs
const adlar = [
  'window', 'document', 'localStorage', 'alert',
  'process', 'Buffer', 'global',
  'fetch', 'URL', 'TextEncoder', 'AbortController', 'structuredClone',
];
for (const ad of adlar) {
  console.log(`${ad.padEnd(16)} ${ad in globalThis ? 'var' : 'yok'}`);
}
node ortam.mjs
window           yok
document         yok
localStorage     yok
alert            yok
process          var
Buffer           var
global           var
fetch            var
URL              var
TextEncoder      var
AbortController  var
structuredClone  var

Çıktı üç öbek gösterir. Birinci öbek yalnızca tarayıcıda bulunur: belge ağacı, sayfa deposu ve kullanıcı arayüzü çağrıları sunucuda karşılıksızdır. İkinci öbek yalnızca sunucu tarafında bulunur: process süreç bilgisini, Buffer ham baytları temsil eder.

Üçüncü öbek daha ilginçtir. fetch, URL, TextEncoder, AbortController ve structuredClone tarayıcı için tanımlanmış arayüzlerdir, ancak dile değil web platformuna aittir. Sunucu çalışma zamanı bunların bir bölümünü aynı sözleşmeyle gerçekleştirir; böylece iki ortamda çalışan kod yazmak, her arayüzün iki ayrı sürümünü tutmayı gerektirmez. Bu ortaklık genişleyen bir kümedir: bir arayüzün belirli bir sürümden itibaren bulunduğu belgelendirilmişse ona güvenilebilir, bulunmadığı ortamlar için ise varlık denetimi yapılır.

global adı, globalThis ile aynı nesneyi gösteren eski bir addır. Yeni kodda globalThis yazmak, aynı ifadenin her iki ortamda da çalışmasını sağlar.

İki Modül Sistemi

Tarayıcıda tek bir modül biçimi vardır. Sunucu çalışma zamanı ise iki biçimi bir arada taşır ve her dosya için birini seçer.

CommonJS, require çağrısıyla eşzamanlı yükleme yapan, module.exports nesnesine yazarak dışa aktaran biçimdir. ES modülleri, import ve export bildirimleriyle çalışan, bağımlılıkları çalıştırmadan önce çözen biçimdir. İkisinin farkı Modüller, Araçlar ve Ekosistem kursunda ayrıntılandırılmıştı; burada önemli olan, seçimin nasıl yapıldığıdır.

Seçim iki kurala bakar: dosya uzantısı ve en yakın paket bildirimi. .cjs uzantılı dosya her zaman CommonJS, .mjs uzantılı dosya her zaman ES modülüdür. .js uzantısında karar, dosyanın bulunduğu dizinden yukarı doğru bulunan ilk package.json dosyasındaki type alanına göre verilir; alan module ise ES modülü, commonjs ise veya alan yoksa CommonJS.

İki biçimin çalışma anındaki farkı ölçülebilir:

// kapsam.cjs
console.log('this === module.exports :', this === module.exports);
console.log('__filename son parca   :', __filename.split('/').pop());
console.log('require turu           :', typeof require);
// kapsam.mjs
console.log('this                   :', this);
console.log('import.meta.url son parca:', import.meta.url.split('/').pop());
console.log('require turu           :', typeof require);
node kapsam.cjs
this === module.exports : true
__filename son parca   : kapsam.cjs
require turu           : function
node kapsam.mjs
this                   : undefined
import.meta.url son parca: kapsam.mjs
require turu           : undefined

CommonJS dosyası bir fonksiyon gövdesi gibi sarmalanır: require, module, __filename ve __dirname adları o sarmalayıcının parametreleridir, genel değildir. ES modülünde bu adlar yoktur; dosyanın kendi konumu import.meta.url üzerinden, bir dosya yolu olarak değil bir adres olarak verilir. Kurs boyunca ES modülleri kullanılacak; CommonJS yalnızca farkın görülmesi gereken yerlerde geçecek.

Yetenek ve Yetki

Asıl fark ad listesinde değil, sürecin ne yapabildiğindedir.

Tarayıcıda çalışan kod, kullanıcının makinesine karşı düşman kabul edilir ve bir kum havuzunda tutulur: keyfi bir dosyayı okuyamaz, keyfi bir bağlantı noktasını dinleyemez, başka bir kaynağa isteği ancak o kaynağın izin verdiği ölçüde atabilir. Bu kısıtlar tarayıcının kullanıcıya verdiği güvencelerdir.

Sunucu çalışma zamanında böyle bir kum havuzu yoktur. Süreç, onu başlatan kullanıcının yetkileriyle çalışır. Linux’a Giriş kursunda kurulan izin modeli burada doğrudan geçerlidir: süreç hangi dosyaları okuyabiliyorsa çalıştırdığınız betik de onları okuyabilir. Aynı kural yazma ve silme için de geçerlidir.

Bu yetki, aşağıdaki kısa dosyada görülür:

// ilk-okuma.mjs
import { readFileSync } from 'node:fs';

const metin = readFileSync('olcumler.ndjson', 'utf8');
const satirlar = metin.trim().split('\n');

console.log('satir sayisi:', satirlar.length);
console.log('ilk kayit   :', JSON.parse(satirlar[0]));

Modül adındaki node: öneki, adın bir yerleşik modülü gösterdiğini bildirir. Önek olmadan da çözümlenir; önekli yazım, aynı adda bir dosya veya paket bulunması durumunda hangisinin kastedildiğini kesinleştirir. Kurs boyunca önekli biçim kullanılacak.

Kursun Çalışma Dosyası

Bu kurs boyunca tek bir somut iş geliştirilecek: uzaktaki ölçüm düğümlerinden gelen kayıtları toplayan, özetleyen ve HTTP üzerinden sunan küçük bir hizmet. Girdi, her satırı bağımsız bir JSON nesnesi olan bir metin dosyasıdır. Aşağıdaki on iki satırı olcumler.ndjson adıyla kaydedin:

{"zaman":"2024-02-07T09:12:44Z","dugum":"kenar-01","metrik":"sicaklik","deger":21.4}
{"zaman":"2024-02-07T09:12:44Z","dugum":"kenar-01","metrik":"nem","deger":48.0}
{"zaman":"2024-02-07T09:13:02Z","dugum":"kenar-02","metrik":"sicaklik","deger":19.8}
{"zaman":"2024-02-07T09:13:02Z","dugum":"kenar-02","metrik":"nem","deger":52.5}
{"zaman":"2024-02-07T09:14:19Z","dugum":"kenar-01","metrik":"sicaklik","deger":21.9}
{"zaman":"2024-02-07T09:14:19Z","dugum":"kenar-03","metrik":"sicaklik","deger":24.1}
{"zaman":"2024-02-07T09:15:30Z","dugum":"kenar-02","metrik":"sicaklik","deger":20.2}
{"zaman":"2024-02-07T09:15:30Z","dugum":"kenar-03","metrik":"nem","deger":41.3}
{"zaman":"2024-02-07T09:16:04Z","dugum":"kenar-01","metrik":"nem","deger":47.2}
{"zaman":"2024-02-07T09:16:04Z","dugum":"kenar-03","metrik":"sicaklik","deger":24.6}
{"zaman":"2024-02-07T09:17:22Z","dugum":"kenar-02","metrik":"sicaklik","deger":20.7}
{"zaman":"2024-02-07T09:17:22Z","dugum":"kenar-01","metrik":"sicaklik","deger":22.3}

Her satırdaki dört alan sırasıyla ölçüm anını, ölçümü gönderen düğümü, ölçülen büyüklüğü ve değeri taşır. Satır başına bir kayıt tutan bu biçim, Kabuk Programlama kursundaki satır tabanlı süzgeçlerle uyumludur: dosyanın tamamını belleğe almadan, satır satır işlenebilir. Bu özellik akışlar konusunda belirleyici olacak.

Dosyayı yerine koyduktan sonra ilk okumayı çalıştırın:

node ilk-okuma.mjs
satir sayisi: 12
ilk kayit   : {
  zaman: '2024-02-07T09:12:44Z',
  dugum: 'kenar-01',
  metrik: 'sicaklik',
  deger: 21.4
}

Bu çıktı, tarayıcıda karşılığı olmayan bir işi gösterir: yerel bir dosya, kullanıcı onayı olmadan, adı verilerek okundu. Kursun geri kalanı bu yeteneğin üzerine kurulur — ve aynı yeteneğin getirdiği sorumluluğu da işler.

Dosya bulunamadığında ortaya çıkan hata, kurs boyunca sık göreceğiniz biçimdedir:

node -e "import('node:fs').then(m => m.readFileSync('yok.ndjson','utf8')).catch(e => console.log(e.code, '|', e.syscall, '|', e.path))"
ENOENT | open | yok.ndjson

ENOENT, işletim sisteminin sistem çağrısından döndürdüğü hata adıdır; syscall hangi çağrının başarısız olduğunu, path hangi yol için olduğunu söyler. Bu üç alan, hata iletisinin metnine bakmadan karar vermenizi sağlar — hata metni değişebilir, kod değişmez.

Özet

  • Dil standardı değer modelini tanımlar; dış dünyaya erişim barındıran ortamın sorumluluğudur. Tarayıcı ve sunucu çalışma zamanı iki ayrı barındıran ortamdır.
  • Genel nesnede üç öbek vardır: yalnızca tarayıcıda bulunanlar, yalnızca sunucuda bulunanlar ve web platformundan devralınan ortak arayüzler.
  • Modül biçimi dosya uzantısıyla (.cjs, .mjs) veya en yakın paket bildirimindeki type alanıyla seçilir; CommonJS dosyası sarmalanır ve require, module, __filename adlarını parametre olarak alır.
  • Sunucu sürecinde kum havuzu yoktur; süreç, kendisini başlatan kullanıcının dosya ve ağ yetkileriyle çalışır.
  • Yerleşik modüller node: önekiyle yazıldığında ad çakışması olasılığı ortadan kalkar; dosya sistemi hataları code, syscall ve path alanlarıyla ayırt edilir.

Sonraki Adım

Bu derste dosya readFileSync ile, yani süreci bekleterek okundu. Tek iş parçacıklı bir sunucuda bekletmenin bedeli ağırdır: bekleyen süre boyunca başka hiçbir istek işlenemez. Sonraki ders, bu bedeli ödememek için kullanılan düzeneği aşama aşama açar — olay döngüsünün hangi sırayla hangi kuyruğu boşalttığını, zamanlayıcıların ne zaman çalıştığını ve girdi/çıktı geri çağrılarının bu sıraya nereden girdiğini ölçülebilir örneklerle gösterir.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat