Takip et

Modern JavaScript Eşzamanlılığı: 2025 ve Sonrası

JavaScript dünyası, yıllar içinde tek iş parçacıklı doğasından sıyrılarak eşzamanlı ve paralel işlem yeteneklerini geliştiren birçok yeniliğe sahne oldu. Günümüzün karmaşık web uygulamaları, yüksek performanslı algoritmalar ve gerçek zamanlı etkileşimler için bu yeteneklere her zamankinden daha fazla ihtiyaç duyuyor. Peki, 2025 itibarıyla modern JavaScript eşzamanlılığı ne anlama geliyor ve geliştiriciler bu güçlü araçları nasıl etkin bir şekilde kullanabilir? Bu makale, JavaScript’in eşzamanlılık evrimini, mevcut teknolojileri ve gelecekteki potansiyelini derinlemesine inceleyecek.

Uzman İpucu: Web uygulamalarınızda kullanıcı deneyimini radikal bir şekilde iyileştirmek için ana iş parçacığını meşgul eden görevleri Web Workers’a devredin. Bu teknikle UI donmalarını büyük ölçüde azaltabilirsiniz!

Neden JavaScript Eşzamanlılığına İhtiyaç Duyarız? Temel Sorunlar Nelerdir?

JavaScript, özünde tek iş parçacıklı (single-threaded) bir dil olarak tasarlanmıştır. Bu, bir zaman diliminde yalnızca tek bir görevin yürütüldüğü anlamına gelir. Tarayıcı ortamında, bu iş parçacığı genellikle “ana iş parçacığı” (main thread) olarak adlandırılır ve hem kullanıcı arayüzünü (UI) render etmekten hem de tüm JavaScript kodunu çalıştırmaktan sorumludur. İşte bu noktada temel bir problem ortaya çıkar: Eğer uzun süren veya yoğun hesaplama gerektiren bir JavaScript görevi ana iş parçacığını meşgul ederse, kullanıcı arayüzü donar, butonlar tıklanmaz, animasyonlar durur ve kullanıcı deneyimi ciddi şekilde kötüleşir. Modern web uygulamaları, bu tür performans darboğazlarını aşmak zorundadır.

Örneğin, büyük bir veri setini işleyen bir algoritma çalıştırdığınızı veya karmaşık bir görüntü manipülasyonu yaptığınızı hayal edin. Bu işlemler saniyeler hatta daha uzun sürebilir. Ana iş parçacığı bu görevi tamamlarken, tarayıcı sayfayı güncelleyemez, scroll hareketlerine yanıt veremez veya herhangi bir kullanıcı girdisini işleyemez. Bu durum, kullanıcının uygulamadan tamamen kopmasına ve kötü bir izlenim edinmesine yol açar. Geliştiriciler olarak amacımız, kullanıcıların akıcı ve hızlı bir deneyim yaşamasını sağlamaktır. Bu amaca ulaşmak için, JavaScript’in temel tek iş parçacıklı yapısını korurken, bazı görevleri ana iş parçacığının dışında, paralel olarak yürütmenin yollarını bulmamız gerekmektedir. İşte tam da bu noktada modern eşzamanlılık API’leri devreye girer. Bu API’ler, uzun süren işlemleri farklı iş parçacıklarına taşıyarak ana iş parçacığının her zaman yanıt verebilir durumda kalmasını sağlar. Dolayısıyla, eşzamanlılık, kullanıcı deneyimini iyileştirmenin yanı sıra, çok daha karmaşık ve performanslı uygulamalar geliştirmemizin de önünü açar.

Eşzamanlılık kavramı, yalnızca tarayıcı ortamıyla sınırlı değildir. Node.js gibi sunucu tarafı JavaScript ortamlarında da yoğun I/O işlemleri veya CPU-yoğun görevler için benzer ihtiyaçlar ortaya çıkar. Node.js’in olay döngüsü (event loop) modeli, I/O işlemlerini asenkron olarak yöneterek yüksek verimlilik sağlasa da, CPU-yoğun görevler yine de iş parçacığını engelleyebilir. Bu nedenle, hem tarayıcı hem de sunucu tarafında paralel işlem yetenekleri, modern JavaScript geliştirmenin vazgeçilmez bir parçası haline gelmiştir. Bu sayede, uygulamalarımız daha ölçeklenebilir, daha performanslı ve daha kararlı hale gelir. Özetle, eşzamanlılık, JavaScript’in performans sınırlarını zorlamak ve kullanıcıya kesintisiz bir deneyim sunmak için kritik bir araçtır.

JavaScript’in Eşzamanlılık Temelleri: Olay Döngüsü, Promise’ler ve Async/Await Nasıl Çalışır?

Modern JavaScript eşzamanlılık araçlarına dalmadan önce, dilin temel eşzamanlılık mekanizmalarını anlamak hayati öneme sahiptir: Olay Döngüsü (Event Loop), Promise’ler ve Async/Await. Bunlar, JavaScript’in asenkron işlemleri tek iş parçacıklı bir ortamda nasıl yönettiğinin belkemiğidir. Olay döngüsü, tarayıcı veya Node.js ortamında JavaScript kodunun yürütülme şeklini organize eden bir mekanizmadır. JavaScript motoru, kodları ana iş parçacığında çalıştırırken, asenkron işlemler (örneğin, ağ istekleri, zamanlayıcılar, kullanıcı olayları) tamamlandığında geri çağırma (callback) fonksiyonlarını bir sıraya, yani “görev kuyruğuna” (task queue veya callback queue) yerleştirir. Olay döngüsü sürekli olarak bu kuyruğu kontrol eder ve ana iş parçacığı boşaldığında, kuyruktaki bir görevi alıp yürütür. Bu yapı sayesinde, uzun süren bir ağ isteği bile ana iş parçacığını bloke etmez; istek arka planda devam ederken ana iş parçacığı başka işleri yapmaya devam edebilir.

Promise’ler, asenkron işlemlerin daha temiz ve yönetilebilir bir şekilde ele alınmasını sağlayan önemli bir yapıdır. Bir Promise, henüz tamamlanmamış ancak gelecekte bir değere dönüşecek veya bir hata fırlatacak bir asenkron işlemin nihai sonucunu temsil eden bir nesnedir. Promise’ler üç durumda olabilir: pending (beklemede), fulfilled (başarılı) veya rejected (başarısız). Promise’ler, iç içe callback’lerin neden olduğu “callback cehennemi” (callback hell) sorununu çözerek kodun okunabilirliğini ve bakımını ciddi şekilde kolaylaştırmıştır. Örneğin, bir API çağrısı yaptığınızda, döndürülen Promise’i .then() metoduyla başarılı sonuçlar için ve .catch() metoduyla hatalar için işleyebilirsiniz. Bu zincirleme yapı, asenkron işlem akışlarını adım adım takip etmeyi mümkün kılar.

Promise’lerin üzerine inşa edilen Async/Await sözdizimi, asenkron kodu senkron koda benzer şekilde yazmamızı sağlayarak okunabilirliği daha da artırmıştır. async anahtar kelimesiyle işaretlenmiş bir fonksiyon, her zaman bir Promise döndürür. Bu fonksiyonun içinde, await anahtar kelimesini kullanarak bir Promise’in çözülmesini bekleyebiliriz. await anahtar kelimesi, Promise çözülene kadar fonksiyonun yürütülmesini duraklatır, ancak bu duraklama ana iş parçacığını bloke etmez. Olay döngüsü, bu sırada diğer görevleri yürütmeye devam eder. Promise çözüldüğünde, async fonksiyon kaldığı yerden devam eder. Bu sayede, hata yönetimi de try...catch blokları ile senkron koddaki gibi yapılabilir. Örneğin, bir veritabanı sorgusu veya bir dosya okuma işlemi, await ile bekletilerek kodun daha sıralı görünmesi sağlanır.


async function veriGetir() {
    try {
        const response = await fetch('https://api.example.com/data');
        if (!response.ok) {
            throw new Error(HTTP Hata kodu: ${response.status});
        }
        const data = await response.json();
        console.log('Veri başarıyla alındı:', data);
        return data;
    } catch (error) {
        console.error('Veri çekme hatası:', error);
        throw error; // Hatayı daha üst seviyeye taşı
    }
}

// Veriyi kullanma
veriGetir()
    .then(data => console.log('İşlenen veri:', data))
    .catch(error => console.error('Genel hata yakalandı:', error));
    

Bu yapılar, JavaScript'in modern eşzamanlılık stratejilerinin temelini oluşturur. Ancak, bu mekanizmalar hala tek bir iş parçacığında çalışır ve CPU-yoğun işlemleri paralel olarak yürütme yeteneğinden yoksundur. İşte bu noktada Web Workers, SharedArrayBuffer ve diğer ileri düzey API'ler devreye girerek gerçek paralelizm imkanları sunar. Dolayısıyla, bu temel mekanizmaları sağlam bir şekilde kavramak, çok iş parçacıklı JavaScript dünyasına adım atmak için ilk ve en önemli adımdır.

Web Workers Nedir ve Ağır İşlemler Nasıl Paralel Hale Getirilir?

Web Workers, JavaScript'in tek iş parçacıklı doğasının getirdiği sınırlamaları aşmak için tasarlanmış, ana iş parçacığından bağımsız olarak çalışan komut dosyalarıdır. Bir Web Worker başlattığınızda, tarayıcı ayrı bir iş parçacığı oluşturur ve bu iş parçacığında worker script'iniz yürütülür. Bu, ana iş parçacığının kullanıcı arayüzünü güncel tutmaya devam ederken, CPU-yoğun hesaplamaları veya uzun süren işlemleri worker'a devrederek uygulamanızın akıcılığını korumasını sağlar. Worker'lar ana iş parçacığına DOM'a erişemezler; bu, onların yalıtılmış bir ortamda çalıştığı anlamına gelir. İletişim, mesajlaşma (postMessage() ve onmessage olay dinleyicileri) yoluyla gerçekleşir.

Web Worker Oluşturma ve Kullanma Adımları:

  1. Worker Script'ini Hazırla: Ayrı bir JavaScript dosyası oluşturun (örneğin, worker.js) ve içinde worker'ın yapacağı işi tanımlayın.
  2. Ana İş Parçacığından Worker'ı Başlat: Ana betiğinizde new Worker('worker.js') ile bir worker örneği oluşturun.
  3. Mesaj Gönder ve Dinle: worker.postMessage(data) ile worker'a veri gönderin ve worker.onmessage ile worker'dan gelen yanıtları dinleyin. Aynı şekilde worker içinde de self.postMessage(result) ile ana iş parçacığına veri gönderilir ve self.onmessage ile ana iş parçacığından gelen mesajlar dinlenir.

// worker.js
self.onmessage = function(event) {
    const sayi = event.data;
    let sonuc = 1;
    for (let i = 2; i <= sayi; i++) {
        sonuc *= i;
    }
    self.postMessage(sonuc); // Sonucu ana iş parçacığına gönder
};
    


// main.js
const myWorker = new Worker('worker.js');

myWorker.onmessage = function(event) {
    console.log('Worker\'dan gelen sonuç:', event.data);
    document.getElementById('sonuc').innerText = Hesaplanan Değer: ${event.data};
};

myWorker.onerror = function(error) {
    console.error('Worker Hatası:', error);
};

function hesaplamayiBaslat() {
    const input = document.getElementById('sayiInput').value;
    const sayi = parseInt(input);
    if (!isNaN(sayi)) {
        myWorker.postMessage(sayi); // Worker'a sayıyı gönder
        document.getElementById('sonuc').innerText = 'Hesaplanıyor...';
    } else {
        alert('Lütfen geçerli bir sayı girin.');
    }
}

// HTML'de bir buton ve bir input ile bu fonksiyon çağrılabilir
// 
// 
// 

Vaka Analizi: Büyük Görüntü İşleme

Bir web uygulaması düşünün ki, kullanıcıların yüklediği yüksek çözünürlüklü fotoğraflara filtreler uygulaması veya yeniden boyutlandırması gerekiyor. Eğer bu işlemler ana iş parçacığında yapılırsa, görüntü büyüdükçe uygulamanın donma süresi de artar. Bu senaryoda, Web Workers kullanmak harika bir çözümdür. Kullanıcı fotoğrafı yüklediğinde, görüntü verileri (örneğin bir ImageData nesnesi veya ArrayBuffer olarak) bir worker'a gönderilir. Worker, bu veriyi alıp tüm filtreleme veya yeniden boyutlandırma işlemlerini bağımsız olarak yapar. İşlem tamamlandığında, sonuçta ortaya çıkan işlenmiş görüntü verisini ana iş parçacığına geri gönderir. Ana iş parçacığı bu veriyi alıp bir elementine çizebilir veya görüntü olarak gösterebilir. Bu sayede, kullanıcı filtreleme işlemi devam ederken bile sayfayı kaydırabilir, başka butonlara tıklayabilir veya uygulamanın diğer bölümleriyle etkileşim kurabilir. Bu durum, özellikle mobil cihazlarda veya düşük güçlü bilgisayarlarda çok daha akıcı bir kullanıcı deneyimi sağlar.

Uzman İpucu: Web Worker'lar arasında karmaşık nesneleri postMessage() ile gönderirken, veri kopyalama maliyetini azaltmak için Transferable Objects kullanmayı düşünebilirsiniz. Özellikle ArrayBuffer gibi büyük verilerde performans artışı sağlar.

Ancak Web Workers'ın da kendi içinde kısıtlamaları vardır. Örneğin, farklı worker'lar doğrudan birbirleriyle veya ana iş parçacığıyla ortak bir belleği paylaşamaz. Her mesajlaşma işleminde verinin kopyalanması gerekir, bu da büyük veri setleri için ek yük getirebilir. İşte bu noktada SharedArrayBuffer gibi daha ileri düzey API'ler devreye girer. Yine de, basit ve orta düzeyde CPU-yoğun görevler için Web Workers, ana iş parçacığının özgürlüğünü korumak adına altın standarttır.

SharedArrayBuffer ve Atomics: Çoklu İş Parçacıkları Arasında Güvenli Veri Paylaşımı

Web Workers, paralel işlem yapma yeteneği sunsa da, iş parçacıkları arasında doğrudan bellek paylaşımı yapmadığı için büyük veri setlerinin sürekli kopyalanması performans darboğazlarına yol açabilir. İşte SharedArrayBuffer (SAB) ve Atomics API'leri tam da bu noktada devreye girer. SAB, birden fazla iş parçacığı (main thread ve Web Workers) tarafından aynı anda okunabilen ve yazılabilen, paylaşılan bir bellek alanı oluşturmanıza olanak tanır. Bu, veri kopyalama ihtiyacını ortadan kaldırarak iş parçacıkları arası iletişimi çok daha verimli hale getirir. Ancak, birden fazla iş parçacığı aynı bellek bölgesine aynı anda erişmeye çalıştığında ortaya çıkan "yarış koşulu" (race condition) sorunları ve tutarsız veri durumları gibi karmaşık senkronizasyon problemleri de beraberinde gelir.

Bu senkronizasyon problemlerini çözmek için Atomics API'leri kullanılır. Atomics, SharedArrayBuffer üzerinde atomik (bölünemez) işlemler yapmayı sağlayan bir dizi statik metot sunar. Atomik bir işlem, tamamlanana kadar diğer iş parçacıkları tarafından kesilemeyen veya aynı bellek konumuna erişemeyen bir işlemdir. Bu, verinin her zaman tutarlı kalmasını sağlar ve yarış koşullarını engeller. Atomics API'si, özellikle wait, notify, add, sub, and, or, xor, exchange, compareExchange gibi metotlar içerir. Bu metotlar, iş parçacıklarının belirli bir koşulun gerçekleşmesini beklemesini (Atomics.wait()) veya bir koşulun gerçekleştiğini diğer iş parçacıklarına bildirmesini (Atomics.notify()) sağlayarak karmaşık senkronizasyon mekanizmaları oluşturmamıza olanak tanır.


// worker.js (örnek)
self.onmessage = function(event) {
    const { sharedBuffer, offset, value } = event.data;
    const sharedArray = new Int32Array(sharedBuffer);

    // Ana iş parçacığının hazır olmasını bekleyin
    Atomics.wait(sharedArray, 0, 0); // sharedArray[0] değeri 0 ise bekle

    // Atomik bir şekilde değeri artırın
    const oldValue = Atomics.add(sharedArray, offset, value);
    console.log(Worker: Eski değer ${oldValue}, Yeni değer ${sharedArray[offset]});

    // Ana iş parçacığını bilgilendirin
    Atomics.notify(sharedArray, 0, 1); // sharedArray[0] için bekleyen 1 iş parçacığını serbest bırak
};
    


// main.js (örnek)
const buffer = new SharedArrayBuffer(4 * Int32Array.BYTES_PER_ELEMENT); // 4 elemanlık Int32 dizisi
const sharedArray = new Int32Array(buffer);

// Başlangıç değerini sıfırlayın
Atomics.store(sharedArray, 0, 0); // İş parçacığı senkronizasyonu için kullanacağız

const worker1 = new Worker('worker.js');
const worker2 = new Worker('worker.js');

worker1.postMessage({ sharedBuffer: buffer, offset: 1, value: 5 });
worker2.postMessage({ sharedBuffer: buffer, offset: 2, value: 10 });

// Worker'ların işlerini yapmasını bekleyelim
console.log('Main: Worker\'ların tamamlamasını bekliyorum...');
Atomics.wait(sharedArray, 0, 0); // sharedArray[0] hala 0 ise bekle (ilk worker için)
Atomics.store(sharedArray, 0, 0); // Sıfırla
Atomics.wait(sharedArray, 0, 0); // sharedArray[0] hala 0 ise bekle (ikinci worker için)


console.log('Main: Tüm worker\'lar tamamlandı.');
console.log('Main: Paylaşılan dizinin son hali:', sharedArray); // [0, 5, 10, 0] veya benzeri
    

Vaka Analizi: Gerçek Zamanlı Veri Panosu

Yüksek performanslı bir finansal ticaret uygulaması veya bir sensör verisi izleme panosu düşünün. Bu tür uygulamalarda, farklı kaynaklardan gelen binlerce veri noktası saniyede güncellenebilir ve bu verilerin hızlıca işlenip kullanıcı arayüzünde gösterilmesi gerekebilir. Eğer bu işlemleri birden fazla worker'a dağıtmak istiyorsak ve bu worker'lar aynı paylaşılan bir bellek alanını kullanarak toplamlar, ortalamalar veya diğer istatistiksel hesaplamalar yapacaksa, SharedArrayBuffer ve Atomics vazgeçilmezdir. Bir worker, belirli bir veri dilimini işleyip sonucu doğrudan paylaşılan arabelleğe yazabilirken, diğer worker'lar farklı dilimleri işleyebilir. Ana iş parçacığı ise paylaşılan arabelleği doğrudan okuyarak verileri görselleştirebilir. Atomics sayesinde, birden fazla worker'ın aynı anda aynı hücreye yazmaya çalışması veya tutarsız veri okuması gibi kritik hataların önüne geçilir. Bu kurulum, devasa veri setlerinin paralel olarak işlenmesini ve gerçek zamanlı güncellemelerle kullanıcıya sunulmasını mümkün kılar, böylece performans artışı dramatik boyutlara ulaşır.

SharedArrayBuffer ve Atomics, JavaScript'i daha düşük seviyeli, bellek tabanlı paralel programlamaya yaklaştırır. Ancak bu güçlü araçlar, doğru senkronizasyon mekanizmaları kurulmadığında karmaşık hatalara yol açabilir. Bu nedenle, bunları kullanırken dikkatli olmak ve eşzamanlılık ilkelerini iyi anlamak büyük önem taşır. Ancak doğru kullanıldığında, JavaScript uygulamalarının performans sınırlarını radikal bir şekilde genişletebilirler.

Service Workers ve Arka Plan Senkronizasyonu: Çevrimdışı Yetenekler ve Performans Optimizasyonu

Service Workers, modern web uygulamalarının çevrimdışı çalışmasını, hızlı yüklenmesini ve güvenilir olmasını sağlayan, tarayıcı tarafından ana iş parçacığından ayrı olarak yürütülen özel bir tür Web Worker'dır. Temel olarak, bir Service Worker bir web sayfası ile ağ arasındaki bir proxy görevi görür. Bu, onun ağ isteklerini kesmesine, önbelleğe almasına ve gerektiğinde önbellekten yanıt vermesine olanak tanır. Bir Service Worker etkinleştirildiğinde ve yüklendiğinde, web uygulaması kapatılmış olsa bile arka planda çalışmaya devam edebilir ve hatta ağ bağlantısı olmasa bile önbelleğe alınmış içeriği sunabilir.

Service Workers'ın gücü sadece önbellekleme ile sınırlı değildir; aynı zamanda "Arka Plan Senkronizasyonu" (Background Sync) gibi ileri düzey özellikler de sunar. Background Sync API'si, bir kullanıcının ağ bağlantısı olmadığında bile bir sunucuyla veri senkronizasyonu yapmasına olanak tanır. Örneğin, kullanıcı bir e-posta taslağı yazıp "gönder" butonuna tıkladığında ancak çevrimdışı olduğunda, Service Worker bu isteği yakalar ve cihaz tekrar çevrimiçi olduğunda otomatik olarak sunucuya gönderilmek üzere sıraya alır. Bu, kullanıcı deneyimini önemli ölçüde iyileştirir çünkü kullanıcı ağ sorunları nedeniyle işlerinin yarım kalmasından endişe etmez.

Service Worker Temel İşlevleri ve Kullanımı:

  • Kurulum ve Etkinleştirme: Bir Service Worker kaydolduğunda, tarayıcı bir 'install' olayı tetikler. Bu olayda, uygulamanızın çalışması için gerekli olan tüm statik varlıkları (HTML, CSS, JS dosyaları, resimler vb.) önbelleğe alabilirsiniz. Kurulum tamamlandığında ve eski Service Worker'lar temizlendiğinde 'activate' olayı tetiklenir.
  • Fetch Olayı: Bu, bir Service Worker'ın en kritik olayıdır. Sayfadan yapılan her ağ isteğini (fetch) keser. Bu noktada, önbellekte belirli bir kaynak olup olmadığını kontrol edebilir, yoksa ağı kullanabilir ve yanıtı önbelleğe alabilirsiniz. Bu stratejilere "Cache-first", "Network-first" veya "Stale-While-Revalidate" gibi isimler verilir.
  • Arka Plan Senkronizasyonu: sync olayını kullanarak çevrimdışı durumda bekleyen istekleri yönetebilirsiniz. Kullanıcı tekrar çevrimiçi olduğunda, tarayıcı Service Worker'ı uyandırır ve bekleyen senkronizasyon görevlerini tetikler.

// sw.js (Service Worker script)
const CACHE_NAME = 'my-app-cache-v1';
const urlsToCache = [
    '/',
    '/index.html',
    '/styles.css',
    '/app.js',
    '/images/logo.png'
];

self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache => {
                console.log('Önbellek açıldı ve dosyalar eklendi');
                return cache.addAll(urlsToCache);
            })
    );
});

self.addEventListener('fetch', event => {
    event.respondWith(
        caches.match(event.request)
            .then(response => {
                if (response) {
                    console.log('Önbellekten yanıt veriliyor:', event.request.url);
                    return response; // Önbellekte varsa önbellekten döndür
                }
                console.log('Ağdan çekiliyor:', event.request.url);
                return fetch(event.request); // Yoksa ağı kullan
            })
    );
});

// Arka Plan Senkronizasyonu örneği
self.addEventListener('sync', event => {
    if (event.tag === 'send-offline-data') {
        event.waitUntil(sendOfflineData());
    }
});

async function sendOfflineData() {
    // Burada IndexedDB'den veya başka bir depolama alanından bekleyen verileri okuyup
    // bir API'ye gönderme mantığı yer alacak
    console.log('Arka plan senkronizasyonu tetiklendi!');
    // Örnek: Gerçek bir API çağrısı
    // const dataToSend = await getFromIndexedDB('offline_posts');
    // await fetch('/api/submit', { method: 'POST', body: JSON.stringify(dataToSend) });
    // console.log('Çevrimdışı veriler başarıyla gönderildi.');
}
    


// app.js (Ana iş parçacığı)
if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js')
            .then(registration => {
                console.log('Service Worker başarıyla kaydedildi:', registration.scope);
            })
            .catch(error => {
                console.error('Service Worker kaydı başarısız oldu:', error);
            });
    });
}

function kaydetOffline() {
    // Örnek: Çevrimdışı bir eylemi kaydetme
    console.log('Çevrimdışı kaydetme denemesi...');
    // Veriyi IndexedDB'ye kaydedin veya benzer bir depolama kullanın
    // Daha sonra Service Worker'ı senkronizasyon için kaydedin
    if ('serviceWorker' in navigator && 'SyncManager' in window) {
        navigator.serviceWorker.ready.then(registration => {
            registration.sync.register('send-offline-data')
                .then(() => console.log('Arka plan senkronizasyonu için kaydedildi'))
                .catch(err => console.error('Senkronizasyon kaydı başarısız:', err));
        });
    }
}

// HTML'de bir buton ile bu fonksiyon çağrılabilir
// 
    

Service Workers, Progressive Web App (PWA) geliştirmenin temel taşlarından biridir. Mobil cihazlarda dahi hızlı ve güvenilir bir deneyim sunarak web uygulamalarını yerel uygulamalara yaklaştırır. Güvenlik açısından, sadece HTTPS üzerinden sunulan sayfalarda çalışır, bu da kullanıcı verilerinin güvenliğini garanti eder. Özetle, Service Workers, sadece eşzamanlılık sağlamakla kalmaz, aynı zamanda web'in çevrimdışı yeteneklerini ve performansını tamamen yeni bir seviyeye taşıyan kritik bir teknolojidir. 2025 ve sonrasında, her modern web uygulamasının bu teknolojiden faydalanması beklenmektedir.

2025 ve Ötesi: Gelecek Beklentileri ve Yeni API'ler

JavaScript ekosistemi, eşzamanlılık ve paralel programlama yeteneklerini sürekli olarak geliştirmekte ve 2025 yılı bu evrimin heyecan verici bir dönemecini temsil etmektedir. Web Workers, SharedArrayBuffer ve Service Workers gibi mevcut API'ler zaten güçlü yetenekler sunsa da, gelecek daha da ileri düzey araçlarla doludur. Özellikle, tarayıcı tabanlı paralelizmde ortaya çıkan yeni standartlar ve Node.js'in sunucu tarafı iş parçacığı yönetimi, geliştiricilere daha önce mümkün olmayan performans ve ölçeklenebilirlik imkanları sunmaktadır.

Node.js Worker Threads: Sunucu Tarafı Paralelizm

Node.js, tek iş parçacıklı ve olay tabanlı mimarisi sayesinde I/O yoğun uygulamalarda oldukça başarılıdır. Ancak, CPU-yoğun görevler (örneğin, şifreleme, veri sıkıştırma, karmaşık matematiksel hesaplamalar) Node.js'in ana iş parçacığını bloke edebilir ve uygulamanın performansını düşürebilir. Bu sorunu çözmek için Node.js, worker_threads modülünü tanıtmıştır. Bu modül, Node.js uygulamalarının birden fazla JavaScript iş parçacığında kodu paralel olarak yürütmesine olanak tanır. Tarayıcıdaki Web Workers'a benzer şekilde, Worker Threads'ler de ana iş parçacığından bağımsızdır ve mesajlaşma yoluyla iletişim kurarlar. Ancak, Node.js ortamında oldukları için I/O işlemleri üzerinde daha fazla kontrole sahiptirler ve SharedArrayBuffer gibi paylaşılan bellek yapılarını da desteklerler.

Bir Node.js Worker Thread'i, sunucunuzun birden fazla CPU çekirdeğinden tam olarak faydalanmasını sağlar. Örneğin, bir API isteği geldiğinde ve bu isteğin bir parçası olarak büyük bir görüntünün işlenmesi gerekiyorsa, bu işlem ayrı bir worker thread'e devredilebilir. Ana iş parçacığı bu sırada diğer gelen istekleri işlemeye devam eder. Böylece, sunucu yanıt verme süresini korurken, CPU-yoğun görevler de etkin bir şekilde tamamlanmış olur. Bu, özellikle mikro hizmet tabanlı mimarilerde veya yüksek trafikli sunucu uygulamalarında kritik bir performans artışı sağlar.


// worker.js (Node.js Worker Thread)
const { parentPort } = require('worker_threads');

parentPort.on('message', (message) => {
    if (message.type === 'calculateFactorial') {
        let result = 1;
        for (let i = 2; i <= message.data; i++) {
            result *= i;
        }
        parentPort.postMessage({ type: 'factorialResult', result });
    }
});
    


// main.js (Node.js Ana Uygulama)
const { Worker } = require('worker_threads');

function calculateFactorialInWorker(number) {
    return new Promise((resolve, reject) => {
        const worker = new Worker('./worker.js');
        worker.postMessage({ type: 'calculateFactorial', data: number });

        worker.on('message', (message) => {
            if (message.type === 'factorialResult') {
                resolve(message.result);
                worker.terminate(); // İşlem bitince worker'ı sonlandır
            }
        });

        worker.on('error', reject);
        worker.on('exit', (code) => {
            if (code !== 0)
                reject(new Error(Worker ${worker.threadId} durduruldu, çıkış kodu: ${code}));
        });
    });
}

async function runCalculations() {
    console.log('Ana iş parçacığı: Hesaplamalar başlıyor...');
    try {
        const result1 = await calculateFactorialInWorker(10);
        console.log(Ana iş parçacığı: 10! = ${result1});

        const result2 = await calculateFactorialInWorker(15);
        console.log(Ana iş parçacığı: 15! = ${result2});
    } catch (error) {
        console.error('Ana iş parçacığı: Bir hata oluştu:', error);
    }
    console.log('Ana iş parçacığı: Hesaplamalar bitti.');
}

runCalculations();
    

WebGPU ve WebAssembly: Yüksek Performanslı Hesaplamalar

2025'te WebGPU'nun daha yaygınlaşması bekleniyor. WebGPU, web üzerinde modern GPU donanımına erişim sağlayan yeni bir API'dir. Sadece 3D grafikler için değil, aynı zamanda genel amaçlı GPU hesaplamaları (GPGPU) için de kullanılabilir. Bu, büyük matris çarpımları, makine öğrenimi modellerinin çıkarımı veya bilimsel simülasyonlar gibi yoğun hesaplama gerektiren görevlerin doğrudan GPU üzerinde çok daha hızlı yürütülebileceği anlamına gelir. JavaScript ile WebGPU API'si üzerinden GPU'ya komutlar gönderilebilir, bu da web uygulamalarının inanılmaz performans seviyelerine ulaşmasını sağlar.

WebAssembly (Wasm) ise, tarayıcıda neredeyse yerel hızlarda çalışan, düşük seviyeli bir ikili kod formatıdır. C, C++, Rust gibi dillerde yazılmış kodların web'e derlenmesini ve JavaScript'in kendisinden çok daha hızlı çalışmasını sağlar. Özellikle CPU-yoğun algoritmalar veya mevcut yerel kütüphanelerin web'e taşınması gerektiğinde Wasm vazgeçilmezdir. Wasm modülleri Web Workers içinde çalıştırılabilir, bu da paralel olarak yüksek performanslı hesaplamalar yapma yeteneği sunar. Gelecekte, Wasm modüllerinin doğrudan SharedArrayBuffer ile etkileşime girmesi ve Atomics API'lerini kullanması, JavaScript ile birleştiğinde web'deki paralel programlama potansiyelini daha da artıracaktır.

Gelecekteki İletişim Standartları: WebTransport

WebTransport, 2025'te daha da olgunlaşması beklenen, düşük gecikmeli, çift yönlü istemci-sunucu iletişimi için yeni bir API'dir. WebSockets'a bir alternatif olarak geliştirilen WebTransport, QUIC protokolünü temel alır ve çoklu akış (multiplexing) ile güvenilirlik gibi gelişmiş özellikler sunar. Bu, özellikle oyunlar, gerçek zamanlı video konferanslar veya yüksek frekanslı veri akışları gibi uygulamalar için idealdir. WebSockets'ın aksine, WebTransport veri kayıplarını daha iyi yönetebilir ve baş-sıra engelleme (head-of-line blocking) sorununu azaltır, bu da daha akıcı ve daha duyarlı gerçek zamanlı deneyimler sunar.

Tüm bu gelişmeler bir araya geldiğinde, 2025 ve sonrası için JavaScript eşzamanlılığı, sadece asenkron I/O yönetiminden çok daha fazlasını ifade ediyor. Gerçek çoklu iş parçacıklı CPU hesaplamaları, GPU hızlandırmalı algoritmalar ve yüksek performanslı ağ iletişimi, web geliştiricilerinin elindeki araç setini genişleterek, her zamankinden daha iddialı ve yetenekli uygulamalar geliştirmelerine olanak tanıyor. Bu, JavaScript'in sadece bir web dili olmaktan çıkıp, genel amaçlı, yüksek performanslı bir programlama platformu olma yolunda attığı dev bir adımdır.

Sonuç ve Sıkça Sorulan Sorular

Modern JavaScript eşzamanlılığı, tek iş parçacıklı bir dilin sınırlarını aşarak web ve sunucu uygulamalarının performansını, yanıt verebilirliğini ve ölçeklenebilirliğini çarpıcı bir şekilde artırmıştır. Olay döngüsü, Promise'ler ve Async/Await gibi temel asenkron mekanizmalarla başlayan bu yolculuk, Web Workers, SharedArrayBuffer ve Atomics ile gerçek paralel programlama yeteneklerine evrildi. Ayrıca, Service Workers sayesinde çevrimdışı destek, arka plan senkronizasyonu ve PWA'lar için temel bir yapı taşı haline geldi. 2025 ve sonrasında ise Node.js Worker Threads, WebGPU ve WebTransport gibi teknolojilerle JavaScript'in yüksek performanslı hesaplama ve gerçek zamanlı iletişim yetenekleri daha da ileriye taşınmaktadır.

Bu makale boyunca, JavaScript'in eşzamanlılık evrimini, temelden ileri düzeye kadar çeşitli API'leri ve bunların gerçek dünya senaryolarında nasıl kullanılabileceğini inceledik. Artık geliştiriciler, UI'ı bloke etmeden yoğun hesaplamalar yapabilir, çevrimdışı ortamlarda dahi veri senkronizasyonu sağlayabilir ve çok çekirdekli işlemcilerin gücünden tam anlamıyla faydalanabilirler. JavaScript, artık sadece etkileşimli web sayfaları oluşturmaktan çok daha fazlasını yapabilen, güçlü ve çok yönlü bir platformdur. Bu eşzamanlılık araçlarını doğru bir şekilde anlamak ve uygulamak, modern web ve sunucu uygulamaları geliştiren her geliştirici için kritik öneme sahiptir.

Sıkça Sorulan Sorular

Web Workers ile Node.js Worker Threads arasındaki temel fark nedir?
Her ikisi de ayrı iş parçacıklarında kod çalıştırmak için kullanılırken, Web Workers tarayıcı ortamında çalışır ve DOM'a erişimi yoktur, Node.js Worker Threads ise sunucu tarafında Node.js ortamında çalışır ve I/O işlemlerine daha fazla erişime sahiptir. Ayrıca, Node.js worker'ları modül sistemini kullanırken, Web Workers'lar kendi scope'larına sahiptir.
SharedArrayBuffer kullanırken neden Atomics API'si gereklidir?
SharedArrayBuffer, birden fazla iş parçacığının aynı bellek alanına doğrudan erişmesini sağlar. Ancak bu durum, aynı anda belleğe yazma veya okuma girişimleri nedeniyle "yarış koşulları" ve veri tutarsızlıkları oluşturabilir. Atomics API'si, bu paylaşılan bellek üzerinde atomik (bölünemez ve kesilemez) işlemler yaparak veri bütünlüğünü ve senkronizasyonu garanti eder, böylece güvenli çoklu iş parçacıklı erişim sağlar.
Service Workers ne tür uygulamalar için en uygundur?
Service Workers, özellikle Progressive Web App'ler (PWA'lar), çevrimdışı yetenek gerektiren uygulamalar, ağ bağımsızlığına ihtiyaç duyan uygulamalar (örneğin, haber okuyucular, e-ticaret siteleri) ve arka planda veri senkronizasyonu veya push bildirimleri gibi özelliklere sahip olmak isteyen tüm web uygulamaları için uygundur. Performansı ve kullanıcı deneyimini önemli ölçüde artırır.
JavaScript'in gelecekteki eşzamanlılık yetenekleri mobil cihazlar için ne anlama geliyor?
Gelecekteki eşzamanlılık yetenekleri, özellikle WebGPU ve WebAssembly, mobil cihazlarda bile daha karmaşık ve performanslı web uygulamalarının çalışmasını sağlayacak. Mobil cihazların donanım gücü arttıkça, bu API'ler sayesinde web uygulamaları mobil platformlarda neredeyse yerel uygulama deneyimi sunabilecek, grafik yoğun oyunlar ve makine öğrenimi gibi alanlarda büyük potansiyel taşıyacaktır. Örneğin, mobil web tarayıcısında çalışan bir 3D oyun, WebGPU ile çok daha akıcı hale gelebilir.
Mobil uyumlu HTML için eşzamanlılık açısından nelere dikkat etmeliyim?
Mobil uyumlu HTML'de eşzamanlılık, kullanıcı deneyimi için kritik öneme sahiptir. Ağır hesaplamaları Web Workers'a taşıyarak ana iş parçacığının serbest kalmasını sağlayın ki kullanıcı arayüzü her zaman yanıt verebilsin. Ayrıca, Service Workers kullanarak çevrimdışı önbellekleme ve arka plan senkronizasyonu ile ağ koşulları ne olursa olsun uygulamanızın hızlı ve güvenilir kalmasını sağlayın. gibi meta etiketlerini kullanmak ve CSS media sorguları (örneğin, @media screen and (max-width: 768px) { ... }) ile duyarlı tasarımlar oluşturmak da temel mobil uyumluluk adımlarıdır. Eşzamanlılık, mobil cihazlarda pil ömrü ve kaynak kısıtlamaları nedeniyle daha da önem kazanır; bu nedenle gereksiz işlemleri minimize etmek veya ertelemek önemlidir.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Mobil sürümden çık