Neler yeni

Yazılım Forum

Tüm özelliklerimize erişmek için şimdi bize katılın. Kayıt olduktan ve giriş yaptıktan sonra konu oluşturabilecek, mevcut konulara yanıt gönderebilecek, itibar kazanabilecek, özel mesajlaşmaya erişebilecek ve çok daha fazlasını yapabileceksiniz! Bu hizmetlerimiz ise tamamen ücretsiz ve kurallara uyulduğu sürece sınırsızdır, o zaman ne bekliyorsunuz? Hadi, sizde aramıza katılın!

JavaScript'te Asenkron Akış Yönetimi: Derinlemesine Bir Bakış

Giriş: Asenkron Programlama Nedir?
JavaScript, doğası gereği tek iş parçacıklı (single-threaded) bir dildir. Bu, aynı anda yalnızca bir işlem yapabileceği anlamına gelir. Ancak web uygulamalarında, sunucudan veri çekme, dosya okuma/yazma, kullanıcı arayüzü güncellemeleri gibi uzun süren işlemler bloklayıcı (blocking) olabilir. Eğer bu işlemler eşzamanlı (synchronous) olarak yürütülseydi, tarayıcı donar ve kullanıcı hiçbir işlem yapamazdı. İşte tam bu noktada asenkron programlama devreye girer. Asenkron kod, uzun süreli bir görevi başlatır ve bu görev tamamlanana kadar diğer kodların çalışmasına izin verir. Görev bittiğinde, sonuçları işlemek üzere bir bildirim alınır. Bu yaklaşım, uygulamaların duyarlı kalmasını sağlar ve daha iyi bir kullanıcı deneyimi sunar.

1. Callback Fonksiyonları: İlk Adım
JavaScript'te asenkron işlemleri yönetmenin en temel yollarından biri callback fonksiyonları kullanmaktır. Bir callback fonksiyonu, başka bir fonksiyonun argümanı olarak geçilen ve ana işlem tamamlandıktan sonra çağrılacak olan bir fonksiyondur.

Kod:
function veriCek(url, callback) {
    // Gerçek bir HTTP isteği simülasyonu
    setTimeout(() => {
        const veri = `URL'den gelen veri: ${url}`;
        callback(veri);
    }, 2000);
}

veriCek("https://api.example.com/data", function(sonuc) {
    console.log(sonuc); // 2 saniye sonra çalışır
});

Callback'lerin Dezavantajları (Callback Hell):
Birden fazla iç içe geçmiş asenkron işlem olduğunda, kodun okunabilirliği ve bakımı zorlaşır. Bu duruma "Callback Hell" veya "Piramit Felaketi" denir.

Kod:
ilkIslem(function(sonuc1) {
    ikinciIslem(sonuc1, function(sonuc2) {
        ucuncuIslem(sonuc2, function(sonuc3) {
            // ... ve böyle devam eder
        });
    });
});

2. Promise'ler: Callback Hell'e Çözüm
ECMAScript 2015 (ES6) ile hayatımıza giren Promise'ler, asenkron işlemleri yönetmek için çok daha yapılandırılmış ve okunabilir bir yol sunar. Bir Promise, henüz tamamlanmamış bir asenkron işlemin nihai sonucunu temsil eden bir nesnedir.

Bir Promise üç olası durumda bulunabilir:
  • Pending (Beklemede): Başlangıç durumu, ne yerine getirilmiş ne de reddedilmiştir.
  • Fulfilled (Yerine Getirilmiş): İşlem başarıyla tamamlanmış ve bir değer döndürmüştür.
  • Rejected (Reddedilmiş): İşlem başarısız olmuş ve bir hata döndürmüştür.

Kod:
function veriCekPromise(url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const basarili = Math.random() > 0.3; // Başarı oranını simüle edelim
            if (basarili) {
                const veri = `Promise ile URL'den gelen veri: ${url}`;
                resolve(veri);
            } else {
                reject(new Error("Veri çekme başarısız oldu!"));
            }
        }, 1500);
    });
}

veriCekPromise("https://api.example.com/promise-data")
    .then(sonuc => {
        console.log("[b]Başarılı:[/b]", sonuc);
        return sonuc.length; // Zincirleme için yeni bir değer döndürme
    })
    .then(uzunluk => {
        console.log("[i]Verinin uzunluğu:[/i]", uzunluk);
    })
    .catch(hata => {
        console.error("[u]Hata:[/u]", hata.message);
    })
    .finally(() => {
        console.log("Promise işlemi tamamlandı.");
    });

Promise Zincirleme (Chaining):
`.then()` metodu her zaman yeni bir Promise döndürür, bu da Promise'leri zincirlemenizi sağlar ve Callback Hell sorununu ortadan kaldırır. Her `.then()` bir önceki Promise'in sonucunu alır.

Promise Kompozisyonu:
Birden fazla Promise'i paralel olarak çalıştırmak veya belirli koşullara göre yönetmek için statik Promise metotları kullanılır:
  • Promise.all(iterable): Verilen tüm Promise'ler yerine getirildiğinde çözülen yeni bir Promise döndürür. Herhangi biri reddedilirse, bu Promise de reddedilir.
  • Promise.race(iterable): Verilen Promise'lerden ilki yerine getirildiğinde veya reddedildiğinde çözülen yeni bir Promise döndürür.
  • Promise.allSettled(iterable): Tüm Promise'ler yerine getirildiğinde veya reddedildiğinde çözülür, her bir Promise'in durumunu ve değerini/nedenini içeren bir dizi döndürür.
  • Promise.any(iterable): Verilen Promise'lerden ilki yerine getirildiğinde çözülen yeni bir Promise döndürür. Eğer hepsi reddedilirse, bir AggregateError ile reddedilir.

Kod:
const p1 = Promise.resolve(3);
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 100));
const p3 = new Promise((resolve, reject) => setTimeout(() => reject("Hata Oluştu!"), 50));

Promise.all([p1, p2])
    .then(sonuclar => console.log("Promise.all:", sonuclar)) // [3, 2]
    .catch(hata => console.error("Promise.all hatası:", hata));

Promise.race([p1, p2, p3])
    .then(sonuc => console.log("Promise.race:", sonuc)) // 3 (en hızlı çözülen)
    .catch(hata => console.error("Promise.race hatası:", hata));

3. Async/Await: Asenkron Kodu Senkron Gibi Yazma
ECMAScript 2017 ile gelen async/await, Promise'ler üzerinde kurulmuş sentaktik bir şekerdir ve asenkron kod yazmayı daha da kolaylaştırır, kodun senkron bir akışta okunmasını sağlar.

async anahtar kelimesi, bir fonksiyonun her zaman bir Promise döndüreceğini belirtir. Bu fonksiyonun içinde await anahtar kelimesini kullanabiliriz.
await anahtar kelimesi, bir Promise'in sonucunu bekler ve Promise çözüldüğünde değerini döndürür. Eğer Promise reddedilirse, await ifadesi bir hata fırlatır.

Kod:
async function veriIsle() {
    try {
        console.log("Veri çekmeye başlanıyor...");
        const veri = await veriCekPromise("https://api.example.com/async-data");
        console.log("[b]Async/Await ile gelen veri:[/b]", veri);
        const islenmisVeri = await islemYapPromise(veri); // Varsayımsal bir Promise döndüren fonksiyon
        console.log("[i]İşlenmiş veri:[/i]", islenmisVeri);
    } catch (hata) {
        console.error("[u]Async/Await hatası:[/u]", hata.message);
    } finally {
        console.log("Async/Await işlemi tamamlandı.");
    }
}

// Varsayımsal bir Promise döndüren fonksiyon
function islemYapPromise(veri) {
    return new Promise(resolve => {
        setTimeout(() => resolve(`İşlenmiş: ${veri}`), 500);
    });
}

veriIsle();

4. JavaScript Event Loop: Perde Arkası
JavaScript'in tek iş parçacıklı doğasına rağmen asenkronluğu nasıl başardığını anlamak için Event Loop (Olay Döngüsü) kavramını bilmek önemlidir.

  • Call Stack (Çağrı Yığını): Çalıştırılmakta olan fonksiyonları tutar. Fonksiyonlar çağrıldıkça yığına eklenir, döndükçe çıkarılır.
  • Web APIs (Tarayıcı API'leri): `setTimeout`, `fetch`, DOM olayları gibi asenkron işlemler tarayıcı (veya Node.js) tarafından sağlanan bu API'ler aracılığıyla yürütülür. Bunlar JavaScript motorunun dışındadır.
  • Callback Queue (Görev Kuyruğu / Task Queue): Web API'leri tarafından tamamlanan asenkron işlemlerin callback fonksiyonları buraya eklenir. `setTimeout` callback'leri buraya gelir.
  • Microtask Queue (Mikrogörev Kuyruğu): Promise callback'leri (`.then()`, `.catch()`, `.finally()`) ve `queueMicrotask` ile eklenen görevler buraya gelir. Bu kuyruk, görev kuyruğundan daha yüksek önceliğe sahiptir.
  • Event Loop: Çağrı yığını boşaldığında, önce Microtask Queue'yu kontrol eder ve oradaki tüm görevleri çağrı yığınına atar. Microtask Queue boşaldığında, Callback Queue'yu kontrol eder ve ilk callback'i çağrı yığınına taşır. Bu süreç sürekli döner.

"JavaScript'in asenkron doğası, Event Loop'un sürekli işleyişi sayesinde kullanıcı arayüzünün donmadan kalmasını ve ağ istekleri gibi uzun süreli işlemlerin arka planda halledilmesini sağlar."

Microtask ve Macrotask (Task) Farkı:
`setTimeout`, `setInterval`, DOM olayları gibi işlemler bir macrotask (görev) oluşturur ve Callback Queue'ya gider.
`Promise.then()`, `async/await` blokları, `queueMicrotask` ise bir microtask (mikrogörev) oluşturur ve Microtask Queue'ya gider.

Önemli: Her bir Event Loop turunda (tick), çağrı yığını boşaldıktan sonra tüm microtask'lar çalıştırılır, ardından sadece bir macrotask çalıştırılır. Bu, Promise'lerin diğer asenkron işlemlere göre daha hızlı çalıştığı anlamına gelir.

Kod:
console.log("1. Başlangıç");

setTimeout(() => {
    console.log("3. setTimeout (Macrotask)");
}, 0);

Promise.resolve()
    .then(() => {
        console.log("2. Promise (Microtask)");
    })
    .then(() => {
        console.log("4. Promise sonrası (Microtask)");
    });

console.log("5. Bitiş");

// Çıktı sırası:
// 1. Başlangıç
// 5. Bitiş
// 2. Promise (Microtask)
// 4. Promise sonrası (Microtask)
// 3. setTimeout (Macrotask)

5. Asenkron Akış Yönetimi için En İyi Uygulamalar

  • Tutarlı Hata Yönetimi: Asenkron işlemlerde hataları yönetmek kritik öneme sahiptir. Promise'ler için `.catch()`, async/await için `try...catch` bloklarını mutlaka kullanın. Hataları yakalamak, uygulamanızın beklenmedik durumlarda çökmesini önler.
  • Asenkron Fonksiyonları Kullanın: Yeni projelerde veya mevcut kodları refactor ederken `async/await` yapısını tercih edin. Bu, kodu daha okunabilir ve bakımı daha kolay hale getirir.
  • Promise.all() ve Promise.race() ile Performans Optimize Edin: Birbirinden bağımsız birden fazla asenkron işlemi aynı anda başlatmak ve sonuçlarını beklemek için `Promise.all()`'ı kullanın. Eğer sadece en hızlı cevaba ihtiyacınız varsa `Promise.race()` uygun olabilir.
  • Dikkatli Zamanlayıcı Kullanımı: `setTimeout` ve `setInterval` gibi fonksiyonları kullanırken, bunların Event Loop üzerindeki etkilerini ve Callback Queue'ya nasıl davrandıklarını anlayın. Minimum gecikme süresi `0` olsa bile, bu işlemler microtask'lardan sonra çalışacaktır.
  • AbortController ile İstekleri İptal Etme: Özellikle uzun süreli ağ istekleri gibi durumlarda, kullanıcı sayfadan ayrıldığında veya yeni bir istek başlattığında önceki isteği iptal etmek için AbortController API'si kullanılabilir. Bu, gereksiz kaynak tüketimini önler.

Sonuç
JavaScript'te asenkron akış yönetimi, modern web geliştirmenin temel taşlarından biridir. Callback fonksiyonlarından başlayıp, Promise'ler ile evrilen ve `async/await` ile zirveye ulaşan bu yolculuk, geliştiricilere güçlü ve esnek araçlar sunar. Event Loop'un çalışma prensiplerini anlamak, daha verimli ve hatasız asenkron kod yazmanın anahtarıdır. Bu teknikleri ustaca kullanarak, kullanıcılar için hızlı, duyarlı ve sorunsuz deneyimler sunan uygulamalar geliştirebilirsiniz. Unutmayın ki, her aracın kendine özgü avantajları ve dezavantajları vardır; doğru aracı doğru senaryoda kullanmak, başarılı asenkron akış yönetiminin sırrıdır. Bu konuda MDN Web Docs gibi kaynaklar sürekli olarak güncel ve detaylı bilgi sunmaktadır.
 
shape1
shape2
shape3
shape4
shape5
shape6
Üst

Bu web sitenin performansı Hazal Host tarafından sağlanmaktadır.

YazilimForum.com.tr internet sitesi, 5651 sayılı Kanun’un 2. maddesinin 1. fıkrasının (m) bendi ve aynı Kanun’un 5. maddesi kapsamında Yer Sağlayıcı konumundadır. Sitede yer alan içerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır.

YazilimForum.com.tr, kullanıcılar tarafından paylaşılan içeriklerin doğruluğunu, güncelliğini veya hukuka uygunluğunu garanti etmez ve içeriklerin kontrolü veya araştırılması ile yükümlü değildir. Kullanıcılar, paylaştıkları içeriklerden tamamen kendileri sorumludur.

Hukuka aykırı içerikleri fark ettiğinizde lütfen bize bildirin: lydexcoding@gmail.com

Sitemiz, kullanıcıların paylaştığı içerik ve bilgileri 6698 sayılı KVKK kapsamında işlemektedir. Kullanıcılar, kişisel verileriyle ilgili haklarını KVKK Politikası sayfasından inceleyebilir.

Sitede yer alan reklamlar veya üçüncü taraf bağlantılar için YazilimForum.com.tr herhangi bir sorumluluk kabul etmez.

Sitemizi kullanarak Forum Kuralları’nı kabul etmiş sayılırsınız.

DMCA.com Protection Status Copyrighted.com Registered & Protected