JavaScript’in Asenkron Doğası: Callback Hell'den Promiselara, Async/Await'e Geçişin Hikayesi

JavaScript’in Asenkron Doğası: Callback Hell'den Promiselara, Async/Await'e Geçişin Hikayesi

**

BFS

JavaScript’in Asenkron Doğası: Callback Hell'den Promiselara, Async/Await'e Geçişin Hikayesi

JavaScript'in dünyasında asenkron programlamanın evrimi, yazılımcıların karşılaştığı en büyük zorluklardan birini oluşturuyor. İster yeni başlamış olun, ister yıllardır JavaScript kodu yazıyor olun, asenkron kodlarla ilgili problemlerle mutlaka karşılaşmışsınızdır. Bir zamanlar JavaScript dünyasında asenkron işlemlerle başa çıkmak, adeta bir kabus gibiydi. Fakat zamanla, bu "callback hell" adı verilen karmaşık yapılar yerini çok daha kullanışlı ve anlaşılır yapılar olan Promises ve async/await gibi modern çözümlere bıraktı. Hadi, JavaScript'in bu asenkron yolculuğuna derinlemesine bir göz atalım.

Bir zamanlar JavaScript geliştiricileri, asenkron işlemleri yönetmek için birbirine iç içe geçmiş *callback* fonksiyonlarını kullanıyordu. Bu, her asenkron işlem tamamlandığında bir callback fonksiyonunun çağrılması anlamına geliyordu. Ancak bu yöntem, hızla karmaşıklaşarak yönetilmesi zor bir hale geliyordu. İşte bu karmaşaya callback hell deniliyordu.

Karmaşanın en büyük nedeni, iç içe geçen fonksiyonlar ve bunların sürekli olarak birbirini takip etmesiydi. Bir fonksiyonun bitmesini bekleyip, sonra diğerini çalıştırmak için aynı şekilde kodu yazmak, projelerin büyüdükçe yönetilemez hale gelmesine neden oluyordu. İşte o dönemde bir geliştirici, neredeyse her yeni asenkron işlem eklediğinde bir kat daha karmaşık hale gelen kodla baş başa kalıyordu.

Aşağıda, callback hell’in nasıl göründüğünü kısa bir örnekle gösterelim:


function fetchData(url, callback) {
  setTimeout(() => {
    console.log(`Veri alındı: ${url}`);
    callback();
  }, 1000);
}

fetchData("api/1", () => {
  fetchData("api/2", () => {
    fetchData("api/3", () => {
      console.log("Tüm işlemler tamamlandı");
    });
  });
});


Bu kod örneği, birden fazla asenkron işlemi ardı ardına gerçekleştirmek için iç içe callback fonksiyonları kullanıyor. Ancak bu yapı, yalnızca basit bir örnekte bile karmaşık hale geliyor. Yöneticisi olunması gereken bir kod, geliştiricinin moralini bozabiliyor.

İşte bu noktada Promises devreye giriyor. JavaScript'in eski callback tabanlı asenkron yapısını geride bırakmasına neden olan Promises, geliştiricilere daha temiz ve okunabilir bir kod yazma olanağı sağladı. Bir Promise, bir asenkron işlemin sonucunu temsil eder. İsterseniz başarılı, isterseniz hata almış olsun, bu sonuçla ilgili işlem yapabileceğiniz bir yapı sunar.

Promises sayesinde, iç içe geçmiş callback fonksiyonlarıyla uğraşmak yerine, asenkron işlemler daha düz bir yapıya kavuşturulabiliyor. İşte bir Promise örneği:


function fetchData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`Veri alındı: ${url}`);
      resolve();
    }, 1000);
  });
}

fetchData("api/1")
  .then(() => fetchData("api/2"))
  .then(() => fetchData("api/3"))
  .then(() => console.log("Tüm işlemler tamamlandı"))
  .catch((error) => console.log("Hata:", error));


Yukarıdaki örnekte, Promise'lerin `.then()` ve `.catch()` metodları kullanılarak, hata yönetimi ve işlem sıralaması çok daha anlaşılır hale gelmiştir. Bir promise tamamlandığında, `.then()` ile bir sonraki işlemi başlatabilirsiniz. Bu, callback hell'e bir son veriyor!

JavaScript'in asenkron yapısındaki bir diğer devrimsel adım ise async/await yapısının ortaya çıkışıydı. Promises, JavaScript'e asenkron işlemlerle başa çıkmak adına büyük bir kolaylık sağlasa da, büyük projelerde bile olsa kodunuzu hala biraz karmaşık hale getirebiliyordu. Async/await ise, Promises’i daha da anlaşılır ve temiz hale getirdi.

Async fonksiyonu, asenkron bir işlemde kullanılacak fonksiyonu işaret eder. Bu fonksiyon içinde, await kullanarak bir Promise’in tamamlanmasını bekleyebilirsiniz. Böylece, asenkron işlemleri sırayla ve çok daha temiz bir şekilde yazabilirsiniz.

Aşağıda, async/await ile yazılmış bir örnek bulunuyor:


async function fetchData(url) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`Veri alındı: ${url}`);
      resolve();
    }, 1000);
  });
}

async function run() {
  await fetchData("api/1");
  await fetchData("api/2");
  await fetchData("api/3");
  console.log("Tüm işlemler tamamlandı");
}

run();


Bu örnekte, await anahtar kelimesi ile her bir işlemin sırasıyla tamamlanması sağlanıyor ve kod oldukça okunabilir hale geliyor. Asenkron programlamanın en temiz hali diyebiliriz.

Peki, tüm bu asenkron yapıları gerçek dünya projelerinde nasıl kullanıyoruz? Örneğin bir web uygulaması geliştiriyorsanız, API entegrasyonları sırasında asenkron işlemlerle sıkça karşılaşırsınız. API'den veri almak, kullanıcı girişi yapmak veya bir dosya yüklemek gibi işlemler asenkron olarak gerçekleşir. Bu süreçte asenkron yapılar sayesinde, kullanıcı deneyimi hiç kesintiye uğramadan işler. Örneğin, bir API'den kullanıcı bilgilerini almak için async/await kullanarak işlemin başarılı bir şekilde sonlanmasını bekleyebiliriz.

Son olarak, asenkron kod yazarken performans optimizasyonuna dikkat etmek çok önemlidir. Asenkron işlemler sırasıyla yapılırken, gereksiz işlemleri ortadan kaldırmak ve her aşamada hata yönetimini düzgün yapmak, uygulamanızın verimli çalışmasını sağlar. Promise'lerde ve async/await yapısında, hataları düzgün şekilde yakalamak için `.catch()` veya `try/catch` blokları kullanmak çok önemlidir. Böylece, herhangi bir hata oluştuğunda programınızın kesilmesini engelleyebilirsiniz.

---

**

İlgili Yazılar

Benzer konularda diğer yazılarımız

ASP.NET Core ile Mobil Uygulama Geliştirme: Cross-Platform Web ve Mobil Uygulama Birleştirme

Günümüzde mobil uygulamalar hayatımızın ayrılmaz bir parçası haline geldi. Akıllı telefonlarımızda geçirdiğimiz zamanın büyük bir kısmını mobil uygulamalar sayesinde geçiriyoruz. Peki, bir mobil uygulama geliştirirken karşılaştığımız zorlukları nasıl...

ASP.NET Core 500 Internal Server Error: Sebepleri ve Çözümleri

Bir web geliştiricisi olarak, karşılaştığınız en zorlayıcı hatalardan biri şüphesiz "500 Internal Server Error"dır. Bu hata, web uygulamanızda her şeyin yolunda gittiğini düşündüğünüz bir anda karşınıza çıkabilir ve tüm projeyi durdurabilir. Ancak merak...

OAuth2 Authentication Error: Nedenleri ve Çözümleri

OAuth2 Authentication Error: Gerçekten Neyin Peşindeyiz?Her geliştirici, kimlik doğrulama hatalarıyla bir noktada karşılaşmıştır. Ama bazen işler kontrolden çıkabiliyor. Eğer bir gün OAuth2 ile çalışırken bir kimlik doğrulama hatası aldığınızda, yalnız...