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 Async/Await Akışı: Asenkron Programlamayı Senkron Gibi Yönetmek

JavaScript Async/Await Akışı: Asenkron Programlamayı Senkron Gibi Yönetmek

JavaScript, doğası gereği tek iş parçacıklı (single-threaded) bir dildir. Bu, her seferinde yalnızca bir işlem gerçekleştirebileceği anlamına gelir. Ancak web geliştirmenin modern dünyasında, ağ istekleri, dosya okuma/yazma işlemleri, veritabanı sorguları gibi uzun süreli ve potansiyel olarak engelleyici (blocking) işlemlerle sıkça karşılaşırız. Bu tür işlemlerin ana iş parçacığını bloke etmesini engellemek için asenkron programlama teknikleri kullanılır. JavaScript ekosistemi, asenkron işlemleri yönetmek için tarihsel olarak birçok yaklaşım geliştirmiştir: geri çağırma fonksiyonları (callbacks), Promise'ler ve en güncel, okunabilir ve güçlü çözüm olan Async/Await. Bu makalede, JavaScript'te Async/Await akışını derinlemesine inceleyeceğiz, nasıl çalıştığını, neden bu kadar popüler olduğunu ve en iyi uygulamalarını öğreneceğiz.

Geri Çağırma Fonksiyonları ve Promise'lerin Kısa Bir Tarihi

Asenkron programlamanın ilk günlerinde, genellikle geri çağırma fonksiyonları kullanılırdı. Bir işlem tamamlandığında çalışacak bir fonksiyonu başka bir fonksiyona argüman olarak geçmek anlamına geliyordu. Bu, basit durumlarda işe yarasa da, iç içe geçmiş birçok asenkron işlem olduğunda "callback hell" (geri çağırma cehennemi) olarak bilinen, okunması ve bakımı zor bir kod yapısına yol açıyordu.

Kod:
getData(function(a) {
    getMoreData(a, function(b) {
        getEvenMoreData(b, function(c) {
            console.log(c);
        });
    });
});

Bu sorunu çözmek için Promise'ler ortaya çıktı. Promise, asenkron bir işlemin nihai tamamlanmasını veya başarısızlığını temsil eden bir nesnedir. Bir Promise üç durumda olabilir:
  • Pending (Beklemede): İşlem henüz tamamlanmadı veya reddedilmedi.
  • Fulfilled (Tamamlandı/Başarılı): İşlem başarıyla tamamlandı.
  • Rejected (Reddedildi/Başarısız): İşlem bir hata nedeniyle başarısız oldu.

Promise'ler, `.then()` ve `.catch()` metotları aracılığıyla daha zincirlenebilir ve okunabilir bir yapı sunarak callback hell sorununu büyük ölçüde hafifletti.

Kod:
getData()
    .then(a => getMoreData(a))
    .then(b => getEvenMoreData(b))
    .then(c => console.log(c))
    .catch(error => console.error("Bir hata oluştu:", error));

Promise'ler, asenkron kod yazma biçimimizi dönüştürdü, ancak yine de `.then()` zincirleri bazı geliştiricilere hala biraz dolambaçlı gelebiliyordu. İşte bu noktada Async/Await devreye girdi.

Async/Await Nedir ve Nasıl Çalışır?

ECMAScript 2017 (ES8) ile tanıtılan Async/Await, Promise'ler üzerine inşa edilmiş sentaktik bir şekerdir (syntactic sugar). Amacı, asenkron kodun, sanki senkron kod yazıyormuş gibi daha okunabilir ve yönetilebilir görünmesini sağlamaktır. Async/Await, Promise'leri *arkaplanda* kullanmaya devam eder; Promise'lerin çalışma şeklini değiştirmez, sadece onlarla etkileşim kurma biçimimizi kolaylaştırır.

1. `async` Anahtar Kelimesi:
Bir fonksiyonu `async` anahtar kelimesiyle işaretlediğinizde, bu fonksiyonun her zaman bir Promise döndüreceğini belirtirsiniz. Fonksiyonun içinde doğrudan bir değer `return` etseniz bile, bu değer otomatik olarak çözülmüş (resolved) bir Promise içine sarılır.

Kod:
async function myFunction() {
    return "Merhaba Async!";
}

myFunction().then(value => console.log(value)); // Çıktı: Merhaba Async!

async function anotherFunction() {
    throw new Error("Bir hata oluştu!");
}

anotherFunction().catch(error => console.error(error.message)); // Çıktı: Bir hata oluştu!

Bu, `async` fonksiyonların her zaman Promise döndürdüğü anlamına gelir; bu da onları `.then()` ve `.catch()` ile kullanabileceğimiz veya başka bir `async` fonksiyon içinde `await` ile bekleyebileceğimiz anlamına gelir.

2. `await` Anahtar Kelimesi:
`await` anahtar kelimesi, yalnızca bir `async` fonksiyonun içinde kullanılabilir. Bir Promise'in tamamlanmasını beklemek için kullanılır ve Promise çözüldüğünde değerini döndürür. Eğer Promise reddedilirse, `await` bir hata fırlatır ve bu hata `try...catch` bloğu ile yakalanabilir.

Kod:
function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function greet() {
    console.log("Başladı...");
    await delay(2000); // 2 saniye bekler
    console.log("2 saniye sonra Merhaba!");
    return "İşlem Tamamlandı";
}

greet().then(message => console.log(message));
console.log("Ana akış devam ediyor..."); // Bu hemen çalışır, greet() beklerken ana akış engellenmez.

Yukarıdaki örnekte görebileceğiniz gibi, `await delay(2000);` satırı, `delay` Promise'i çözülene kadar `greet` fonksiyonunun yürütülmesini geçici olarak duraklatır. Ancak bu duraklama, JavaScript'in ana iş parçacığını bloke etmez. Bunun yerine, `greet` fonksiyonunun kontrolünü çalışma zamanına geri verir ve `delay` Promise'i çözüldüğünde yürütülmesine devam etmek üzere işaretlenir. Bu, `Ana akış devam ediyor...` çıktısının `2 saniye sonra Merhaba!` çıktısından önce gelmesini sağlar. İşte bu, Async/Await'in gücüdür: asenkron işlemleri senkron bir şekilde yazıyormuş gibi hissetmenizi sağlar, ancak altta yatan non-blocking (engellemeyen) doğasını korur.

Async/Await ile Hata Yönetimi

Promise'lerde hataları `.catch()` ile yakalarken, Async/Await ile standart `try...catch` bloklarını kullanabiliriz. Bu, asenkron hata yönetimini senkron koda çok daha benzer hale getirir ve kodun okunabilirliğini artırır.

Kod:
async function fetchData(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error(`HTTP hatası! Durum: ${response.status}`);
        }
        const data = await response.json();
        return data;
    } catch (error) {
        console.error("Veri alınırken bir hata oluştu:", error);
        // Hatayı yukarıya taşımak için tekrar fırlatılabilir
        throw error;
    }
}

// Başarılı senaryo
fetchData('https://jsonplaceholder.typicode.com/todos/1')
    .then(data => console.log("Veri başarıyla alındı:", data))
    .catch(err => console.error("Dışarıdan yakalanan hata (başarılı senaryo):", err));

// Hatalı senaryo (geçersiz URL)
fetchData('https://geçersiz-adres.com/api/data')
    .then(data => console.log("Veri başarıyla alındı (hatalı senaryo):", data))
    .catch(err => console.error("Dışarıdan yakalanan hata (hatalı senaryo):", err));

`try` bloğu içindeki herhangi bir `await` işlemi reddedilirse (yani, Promise başarısız olursa), yürütme hemen `catch` bloğuna atlar. Bu, asenkron işlemlerde bile tanıdık ve sezgisel bir hata yönetimi deseni sağlar.

Paralel Asenkron İşlemler

Bazen birden fazla asenkron işlemi aynı anda başlatmak ve hepsinin tamamlanmasını beklemek isteyebiliriz. `await` tek başına kullanıldığında, her bir Promise'in bir diğeri başlamadan önce bitmesini bekler, bu da seri bir yürütme anlamına gelir. Paralel yürütme için `Promise.all()` veya `Promise.allSettled()` gibi Promise yöntemlerini `await` ile birlikte kullanabiliriz.

Kod:
async function fetchMultipleData() {
    console.log("Paralel veri çekme başladı...");
    const url1 = 'https://jsonplaceholder.typicode.com/todos/1';
    const url2 = 'https://jsonplaceholder.typicode.com/posts/1';
    const url3 = 'https://jsonplaceholder.typicode.com/users/1';

    try {
        const [todo, post, user] = await Promise.all([
            fetch(url1).then(res => res.json()),
            fetch(url2).then(res => res.json()),
            fetch(url3).then(res => res.json())
        ]);

        console.log("Tüm veriler başarıyla alındı:");
        console.log("Todo:", todo);
        console.log("Post:", post);
        console.log("User:", user);
    } catch (error) {
        console.error("Paralel veri çekme sırasında bir hata oluştu:", error);
    } finally {
        console.log("Paralel veri çekme tamamlandı.");
    }
}

fetchMultipleData();

Yukarıdaki örnekte, `fetch` istekleri hemen hemen aynı anda başlatılır ve `await Promise.all(...)` ifadesi, tüm Promise'ler çözülene kadar bekler. Eğer Promise'lerden herhangi biri reddedilirse, `Promise.all()` bir hata fırlatır ve `try...catch` bloğu tarafından yakalanır.

Eğer tüm Promise'lerin sonucunu (başarılı veya başarısız) bilmek ve bir hatanın diğer Promise'leri engellemesini istemiyorsanız, `Promise.allSettled()` kullanabilirsiniz.

Kod:
async function fetchAllWithSettled() {
    console.log("Promise.allSettled ile veri çekme başladı...");
    const url1 = 'https://jsonplaceholder.typicode.com/todos/1';
    const url2 = 'https://geçersiz-adres.com/api/data'; // Hatalı URL
    const url3 = 'https://jsonplaceholder.typicode.com/users/1';

    const results = await Promise.allSettled([
        fetch(url1).then(res => res.json()),
        fetch(url2).then(res => res.json()).catch(err => ({ status: 'rejected', reason: err.message })), // Hatalı fetch'i yakala
        fetch(url3).then(res => res.json())
    ]);

    console.log("Tüm işlemler tamamlandı (başarılı veya başarısız):
", results);

    results.forEach((result, index) => {
        if (result.status === 'fulfilled') {
            console.log(`İşlem ${index + 1} başarılı:`, result.value);
        } else {
            console.error(`İşlem ${index + 1} başarısız:`, result.reason);
        }
    });
    console.log("Promise.allSettled ile veri çekme tamamlandı.");
}

fetchAllWithSettled();

Async/Await Kullanımının Avantajları ve Dikkat Edilmesi Gerekenler

Avantajları:
  • Okunabilirlik: Asenkron kodun senkron koda benzer şekilde yazılmasını sağlayarak kodun okunabilirliğini ve anlaşılırlığını büyük ölçüde artırır.
  • Basit Hata Yönetimi: `try...catch` blokları sayesinde tanıdık bir hata yönetimi mekanizması sunar.
  • Hata Ayıklama (Debugging): `await` sayesinde, kodda sanki senkron bir işlem varmış gibi adım adım ilerleyebilir ve hata ayıklaması daha kolay hale gelir. Promise zincirlerindeki hata ayıklama bazen daha zorlayıcı olabiliyordu.
  • Daha Az Boilerplate: Promise'lerdeki `.then()` ve `.catch()` zincirlerine kıyasla daha az tekrar eden kod gerektirir.

Dikkat Edilmesi Gerekenler:
  • `await` Sadece `async` Fonksiyonlarda: `await` anahtar kelimesini yalnızca `async` olarak tanımlanmış bir fonksiyonun içinde kullanabilirsiniz. Aksi takdirde bir `SyntaxError` alırsınız.
  • Bloklamayan Doğa: `await`, fonksiyonun kendisini duraklatır ancak ana iş parçacığını bloke etmez. Bu, uygulamanızın duyarlı kalmasını sağlar.
  • Farkında Olmadan Seri Yürütme: Birden fazla Promise'i `await` ile ardı ardına çağırmak, bunları seri olarak yürütür. Paralel yürütme için `Promise.all()` veya `Promise.allSettled()` kullanmayı unutmayın.
  • Top-Level `await`: Modül dışı kodda `await` kullanmak (yani herhangi bir `async` fonksiyonun dışında) varsayılan olarak desteklenmezdi. Ancak modern JavaScript modüllerinde (ES Modülleri) artık top-level `await` desteklenmektedir, bu da özellikle tek dosyalık script'ler veya modül başlatmalarında oldukça kullanışlıdır.

"Async/Await, JavaScript'in asenkron programlama paradigmasını bir sonraki seviyeye taşıyarak geliştiricilere daha zarif ve sezgisel bir deneyim sunmuştur."

Sonuç

Async/Await, JavaScript'teki asenkron programlamayı basitleştiren ve kod kalitesini artıran güçlü bir özelliktir. Promise'lerin temelindeki gücü korurken, callback hell ve karmaşık Promise zincirlerinin getirdiği zorlukları aşmamızı sağlar. Modern JavaScript geliştirmesinde, özellikle ağ istekleri, dosya işlemleri veya veritabanı etkileşimleri gibi I/O yoğun işlemlerle uğraşırken Async/Await'i etkin bir şekilde kullanmak, daha temiz, daha bakımı kolay ve daha anlaşılır kod yazmanın anahtarıdır. Asenkron akışı yönetmek artık bir karmaşa değil, sezgisel bir süreç haline gelmiştir.

MDN Async Function Referansı ve diğer kaynaklar aracılığıyla konuyu daha da derinlemesine inceleyebilirsiniz. Unutmayın, pratik yapmak öğrenmenin en iyi yoludur! Kendi Async/Await projelerinizi oluşturarak bu kavramları pekiştirmeye devam edin.
 
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