Asynchronous JavaScript: Callback, Promise ve Async/Await

Mehmet Demirel
13 min readDec 2, 2023

Herkese merhaba,

Bugün, JavaSript’in temel yapı taşlarından biri olan Asynchronous JavaScript (Asenkron/Eşzamansız JavaScript) konusunu ele alacağız. Uygulamalarınızın (backend/frontend) hızlı ve etkileşimli olmasını sağlayan bu konsept, geleneksel Synchronous (Senkron/Eşzamanlı) programlamadan ayrılarak daha verimli ve performanslı bir yaklaşım sunar. İlk başlarda çok karmaşık gelebilir ancak bu makale ile bu işi sizinle çözeceğiz :). “Callback Functions”(Geri Arama/Çağırma Fonksiyonları), “Promises”(Vaatler/Sözler) ve “Async/Await”(Eşzamansız — Asenkron/Bekle) yapılarını detaylı bir şekilde inceleyerek, bu güçlü konseptleri anlamanız konusunda yardımcı olacağım.

Synchronous Nedir?

Synchronous programming, bir bloklama mimarisi kullanır; bu nedenle her işlem bir öncekinin tamamlanmasını beklemek zorundadır. Her görev, bir sonraki işleme geçmeden önce bir yanıt bekler. Bu programlama tekniği, işlemlerin sırasıyla ve adım adım gerçekleştiği bir yapı sunar. Her bir işlem adımının tamamlandığında ise bir sonraki işlem adımına geçilir. Yani, her adımın sırayla tamamlanması, işlemin devam edebilmesi için kritiktir. Bu durum, bir adımın tamamlanmasının, bir sonraki adımın başlamasına olan bağımlılığını vurgular. Örneğin, bir dosya okuma işlemi gerçekleştirildiğinde, program dosyanın içeriğini okumak için bekler ve bu işlem tamamlandıktan sonra diğer işlemlere geçer.

Peki bunu gerçek dünyaya yansıtarak nasıl anlayabiliriz?

Günlük hayatta synchronous programming nasıl çalıştığını anlamak için bir lüks restorandaki yemek siparişi sürecini düşünelim.

Akşam kendinize şıklık olsun diye lüks bir restorantta yer ayırttığınızı ve oraya yemeğe gideceğinizi düşünün. Restorant’a gittiğinizde sizi masanızda Garson karşılar. Siz bu esnada Garson’a yemek siparişinizin iletirsiniz. Garson aldığı siparişi Şef’e götürür ve Şef yemeğinizi tamamen yapana kadar yemeğinizle ilgilenir. Yemek hazır olduğunda Garson size yemeğinizi teslim eder ve afiyetle yersiniz. Daha sonra Garson başka masalara sipariş almak üzere gider.

Özet olarak buradaki sıralı ilerleyiş synchronous programmingin temel prensiplerini belirtir. Şef yemek siparişinizi aldığında sizin yemeğinizin yapılıp tamamen Garson’a teslim edilmesini bekler ve bir sonraki müşterinin yemek yapma aşamalarına geçer. Bu örneğimizi bir de kod ile anlamaya çalışalım.

function takeOrder(order) {
console.log(`Sipariş alındı: ${order}`);
const cookedMeal = chefPrepareMeal(order);
serveMeal(cookedMeal);
}

function chefPrepareMeal(order) {
console.log(`Şef, siparişi alarak yemeği hazırlıyor: ${order}`);
console.log('Yemek hazır!');
return order;
}

function serveMeal(order) {
console.log(`Garson, müşteriye siparişi olan ${order}'i servis ediyor.`);
}

const order = 'Izgara levrek';

console.log(`Garson, müşteriden siparişi alıyor: ${order}`);

takeOrder(order);

console.log('Garson başka masalara sipariş almak üzere gidiyor.');

Asynchronous Nedir?

Asynchronous programming, bir programın işlemlerini asynchron (eşzamansız) olarak yürütebilme yeteneğini ifade eden bir programlama yaklaşımıdır. Geleneksel synchron programming farklı olarak, asynchron programming sayesinde bir işlem tamamlanırken diğer işlemlerin program tarafından beklenmesi gerekmez. Bu yaklaşım, özellikle uzun süren işlemleri (örn: web sayfasının veri çekme işlemi) daha verimli bir şekilde yönetme konusunda önemli avantajlar sunar. Bir işlemin tamamlanmasını beklemek yerine, programın diğer işlemleri hızlı bir şekilde yürütmesine olanak tanır. Bu sayede, kullanıcı arayüzleri daha hızlı ve akıcı bir deneyim sunar. Ayrıca, bloklama olayını aşarak programın sürekli çalışmasını sağlar. Synchronous programming’in tam tersi olarak, asynchronous programming, programın beklemesini minimize ederek daha dinamik ve etkili bir çalışma şekli sunar. Örneğin, diyelim ki, bir web sitesinde dolaşıyorsunuz. Bu sırada, bir butona tıkladığınızda veri çekilen bir işlem başlattınız. Eğer bu işlem asenkron olmasaydı, sayfa bloklanır ve arayüzü kullanamazdınız. Ancak asenkron programlama, hala veri çekiliyor olsa bile başka işlemler yapmanıza olanak tanır.

Peki bunu gerçek dünyaya yansıtarak nasıl anlayabiliriz?

Bir anda canınız kahve içmek istiyor ve kendinizi sokağa atıyorsunuz. Kendinizi self-servis hizmet veren tatlı bir kafenin önünde buluyorsunuz ve içeri adım atıyorsunuz. Kasaya yaklaştığınızda önünüzde iki kişi olduğunu fark ediyor ve beklemeye başlıyorsunuz.

İlk sırada bekleyen kişi, kahvesinin nasıl olması gerektiğini kasadaki elemana anlatıyor. Kasadaki eleman, kahvenin hazır olduğunda yan taraftan alabileceğini belirterek kahve makinesine siparişi giriyor.

Bu sırada, eleman diğer (2nci) müşteriye dönerek siparişini alıyor. Kasadaki eleman, bu bilgileri alıp tekrar kahve makinesine yöneliyor. O sırada, ilk müşterinin siparişi hazır ve müşteriye teslim ediliyor.

Bu süreçte, ilk müşterinin siparişi, kasadaki elemanın kahve makinesine siparişi girmesiyle başlıyor. Bu işlem, kasadaki elemanın diğer müşterinin siparişini almasına engel olmuyor. Yani, kasadaki eleman aynı anda iki işlemi gerçekleştirebiliyor.

Sonrasında, 2. müşterinin siparişi kahve makinesine giriliyor ve tekrar kasaya dönülüyor. Şimdi sıra bizde. Siparişimiz alınıyor ve aynı süreç tekrarlanıyor.

Bu süreçte, ikinci müşterinin siparişi, kasadaki elemanın ilk müşterinin siparişini teslim etmesiyle başlıyor. Bu işlem, kasadaki elemanın bizim siparişimizi almasına engel olmuyor. Yani, kasadaki eleman aynı anda iki işlemi gerçekleştirebiliyor.

Asynchronous programming, bir işlemin tamamlanması, diğer işlemlerin başlamasına engel olmuyor. Yani, birden fazla işlem aynı anda gerçekleştirilebiliyor. Bu, programların daha hızlı ve verimli çalışmasını sağlıyor.

Kahve alma süreci, asynchronous programming genel çalışma prensibinin bir örneğidir. Birden fazla işlem aynı anda gerçekleştirilebilir ve her işlem, bir öncekinin sonuçlarıyla şekillenir. Bu, programların daha hızlı ve verimli çalışmasını sağlar. Bu örneğimizi bir de kod ile anlamaya çalışalım.

/* Müşteri nesnelerinin bulunduğu dizi. Her bir müşterinin id,
isim ve kahve türü bilgileri bulunuyor. */
const customers = [{
id: 1,
name: 'Leyla',
coffeeType: 'Latte',
},
{
id: 2,
name: 'Okan',
coffeeType: 'Espresso',
},
{
id: 3,
name: 'Mehmet',
coffeeType: 'Turkish Coffee',
},
];

// Müşterinin kahvesinin hazır olduğunu belirten mesajı yazdıran fonksiyon.
function makeCoffee(customer) {
console.log(`${customer.name}'s ${customer.coffeeType} is ready.`);
};

// Her bir müşterinin siparişini işleyen fonksiyon.
function orderCoffee(customerIndex) {
// Temel durum: Tüm müşteriler işlendiğinde, 3 saniye sonra bir mesaj yazdır.
if (customerIndex >= customers.length) {
setTimeout(() => {
console.log('All orders are received.');
}, 3000);
return;
}

// Diziden mevcut müşteriyi al.
const customer = customers[customerIndex];

// Siparişin alındığına dair bir mesaj yazdır.
console.log(`Order received from ${customer.name}.`);

/* Siparişin hazırlanmasını simüle etmek için
iç içe geçmiş setTimeout'ler kullanılıyor. */
setTimeout(() => {
console.log(`${customer.name}'s order is being prepared...`);

/* Kahvenin yapılmasını simüle etmek için
iç içe geçmiş setTimeout kullanılıyor. */
setTimeout(() => {
makeCoffee(customer);

// Müşterinin kahvesini almasını simüle etmek için 1 saniye bekleniyor.
setTimeout(() => {
console.log(`${customer.name} is taking his/her coffee.`);
}, 1000);
}, 2000);
}, 3000);

// Bir sonraki siparişin işlenmesi için 4 saniye sonra plan yapılıyor.
setTimeout(() => {
orderCoffee(customerIndex + 1);
}, 4000);
};

// İlk müşteri ile başlayarak siparişleri işlemeye başla (index 0).
orderCoffee(0);
out

Callback Functions

Callback function, bir başka function’a args(argüman) olarak iletilen ve main functionın yürütülmesi tamamlandıktan sonra çağrılan bir function’dır. Main function, args olarak bir callback function çağrılır ve main function tamamlandığında, bir sonuç sağlamak için callback function çağırır. Callback function, asynchron bir işlemin sonuçlarını blokajsız(bloklamadan/engellemeden) bir şekilde işlemenize olanak tanır; bu da işlem yürütülürken programın çalışmaya devam edebileceği anlamına gelir.

Callback function, asynchron işlemlerin sonuçlarını engellemesiz bir şekilde işlemek için kullanılır. Zaman uyumsuz işlemler, ağ istekleri, dosya girdi-çıktısı ve veritabanı sorguları gibi tamamlanması bir miktarda zaman alan işlemlerdir. Bu işlemler synchron olarak yürütülseydi, program donar ve devam etmeden önce işlemin tamamlanmasını beklerdi. Bu durum, program tepkisiz görüneceğinden kötü bir kullanıcı deneyimine yol açabilir.

Callback function, işlem arka planda yürütülürken kodu çalıştırmaya devam etmenizi sağlar. İşlem tamamlandığında, geri arama işlevi işlemin sonucuyla birlikte çağrılır. Bu şekilde, programın duyarlı kalmasını ve kullanıcı deneyiminin etkilenmemesini sağlayabilirsiniz.

function brewCoffeeAndPrepareSnack(callback) {
function brewCoffee(cb) {
setTimeout(() => {
cb(null, 'Coffee');
}, 1000);
}

function prepareSnack(cb) {
setTimeout(() => {
cb(null, 'Snack');
}, 500);
}

brewCoffee((error, coffee) => {
if (error) {
callback('Error brewing coffee: ' + error);
} else {
console.log(coffee);
prepareSnack((error, snack) => {
if (error) {
callback('Error preparing snack: ' + error);
} else {
console.log(snack);
callback(null, 'Coffee and snack are ready.');
}
});
}
});
}

brewCoffeeAndPrepareSnack((error, result) => {
if (error) {
console.error(error);
} else {
console.log(result);
}
});

brewCoffeeAndPrepareSnack function, iç içe geçmiş iki function tanımlayarak başlar: brewCoffee ve prepareSnack. Bu functionlar sırasıyla kahve yapma ve atıştırmalık hazırlama gibi async görevleri temsil eder. Her bir function, async görev tamamlandığında çağrılacak olan bir callback functionı args(argüman) olarak alır.

brewCoffee function, async kahve yapma sürecini simüle etmek için setTimeout kullanır. 1000 milisaniyelik (1 saniye) bir gecikme sonrasında callback function, kahve yapma sürecinin sonucu ile çağrılır. Eğer kahve yaparken herhangi bir hata oluşmuşsa, callback kahve yerine bir error mesajı ile çağrılır.

prepareSnack function da benzer şekilde async atıştırmalık hazırlama sürecini simüle etmek için setTimeout kullanır. 500 milisaniyelik (yarım saniye) bir gecikme sonrasında callback function, atıştırmalık hazırlama sürecinin sonucu ile çağrılır. Eğer atıştırmalık hazırlarken herhangi bir hata oluşmuşsa, callback atıştırmalık yerine bir error mesajı ile çağrılır.

brewCoffeeAndPrepareSnack function ana bölümü, bir callback function args olarak alarak brewCoffee function çağırır. Bu callback function, kahve yaparken herhangi bir error olup olmadığını kontrol eder. Eğer error yoksa, callback function prepareSnack function çağırarak bir başka callback function args olarak geçer. Bu iç içe geçmiş callback function, benzer şekilde error kontrol eder ve nihai callback function genel sonuç ile çağrır.

Son callback function, kahvenin ve atıştırmalığın hazırlandığı kod parçasının en üst düzeyinde çağrılır. Bu callback function, errorları kontrol eder ve sonucu uygun şekilde kaydeder.

Artıları:

  • Asenkron İşlemleri Yönetme: Özellikle async işlemleri yönetme konusunda etkilidir. Bu sayede, uzun sürecek işlemlerin sonuçları beklenirken diğer işlemler devam edebilir.
  • Esneklik: Callback‘ler, functionları diğer functionlara args olarak geçme yeteneği sağlar. Bu, kodun modüler ve yeniden kullanılabilir olmasına olanak tanır.
  • Kolay Uygulanabilirlik: Callback’ler, JavaScript ve diğer dillerde (Python, CSharp etc.) doğal bir şekilde kullanılır. Bu nedenle, async programming konseptlerini anlamak ve uygulamak daha kolaydır.
  • Hata Kontrolü: Callback’ler, hata yönetimi için uygun bir yapı sağlar. Hatalar, callback funtionları içinde ele alınabilir ve uygun şekilde işlenebilir.

Eksileri:

  • Callback Hell (Callback Cehennemi): Çok sayıda iç içe geçmiş callback functionlar oluşturmak, kodun okunabilirliğini azaltır ve “callback hell” durumuna yol açar. Bu durum, kodun karmaşıklığını artırır ve hem kullanılabilirliğini hem de geliştirme sürecini zorlaştırır.
  • Sıralama ve Hata Takibi Zorlukları: Callback functionları kullanılırken, işlemlerin sıralanması ve hata takibi bazen zor olabilir. Özellikle çok sayıda callback içeren karmaşık senaryolarda bu sorunlar daha belirgin hale gelebilir.
  • Zor Debug Etme: Callback’ler, hataların kaynağını belirlemeyi ve kodu hata ayıklamayı zorlaştırabilir. Callback functionları iç içe geçtikçe, hatanın kaynağını bulmak daha karmaşık hale gelebilir.
  • Kod Karmaşıklığı: Callback’ler, kodun karmaşıklığını artırabilir, özellikle büyük projelerde ve çok sayıda async işlemin olduğu durumlarda kod karmaşasına sebep olacaktır.

Promise

Promise (Vaat/Söz) object (obje/nesne), gelecekte bir şeyin gerçekleşeceğine dair güvence veya taahhüttür. Belirli bir sonuca veya neticeye yönelik bir taahhüdü ifade eder ve çoğumuz büyük olasılıkla haytımızda birine/birilerine vaatte bulunmuşuzdur. Örneğin, bir arkadaşınız doğum gününüzde sürpriz bir parti düzenleme sözü verdi. Belirtilen tarihe geldiğinde parti başarıyla gerçekleşirse (çözülmüş vaat), vaat yerine getirilmiş olur. Ancak, beklenen etkinlik gerçekleşmezse veya bir aksilik olursa (örneğin, beklenmedik bir durum nedeniyle iptal), bu durumda vaat reddedilmiş olacaktır.

Promise, JavaScript’te kullanılan bir Object olup, bir asynchronous operasyonun sonucunun başarılı bir şekilde tamamlanmasını veya başarısız olmasını temsil eder. Bu nesnenin üç farklı durumu vardır: Pending (Beklemede/İşleniyor), Fulfilled (Çözülmüş/Başarılı) ve Rejected (Reddedilmiş/Hatalı). Pending durumu, promise’in başlangıç ​​durumudur ve asynchronous operasyon henüz tamamlanmamıştır. Fulfilled durumu, asynchronous operasyonun başarıyla tamamlandığı durumdur. Rejected durumu, asynchronous operasyonun bir hata ile sonuçlandığı durumdur.

  • Pending (Beklemede): Promise’in başlangıç ​​durumudur. Bu durumda, asynchronous operasyon henüz tamamlanmamıştır. Promise, asynchronous operasyonun tamamlanmasını beklemektedir.
  • Fulfilled (Çözülmüş): Asynchronous operasyonun başarıyla tamamlandığı durumdur. Bu durumda, promise, asynchronous operasyonun sonucunu temsil eden bir değer üretir.
  • Rejected (Reddedilmiş): Asynchronous operasyonun bir hata ile sonuçlandığı durumdur. Bu durumda, promise, asynchronous operasyonun hatasını temsil eden bir hata nesnesi üretir.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Promise’leri kullanmak için öncelikle bir promise object oluşturmamız gerekir. Bu, JavaScript için new Promise() işlevini kullanarak yapılır. new Promise() işlevi, bir resolve() ve bir reject() args(argümanlarını) alır. resolve() arg(argümanı), promise'in fulfilled durumuna geçmesini sağlar. reject() arg(argümanı), promise'in rejected durumuna geçmesini sağlar.

Promise sonuçlarını elde etmek için then() veya catch() yöntemlerini kullanırız. then() yöntemi, promise'in fulfilled durumuna geçtiğinde çağrılan bir callback function sağlar. catch() yöntemi, promise'in rejected durumuna geçtiğinde çağrılan bir callback function sağlar.

Promise Fullfield

Aşağıdaki kod bloğu, bir Promise oluşturarak içindeki asynchronous işlemi simüle eder. Bu işlem, bir saniye içinde rastgele bir sayı üretip resolve çağrısı yapılarak işlem başarılı hele getirlilr. Ardından, oluşturulan Promise’in then metodunu kullanarak başarılı duruma tepki verir. Şimdi, bu örnek üzerinden Promise kullanımının temel prensiplerini anlamaya başlayalım.

const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.floor(Math.random() * 10);
resolve(`İşelem başarılı ve tamamlandı. Sayı: ${randomNumber}`)
}, 1000);
});

promise.then(value => console.log(value))
// İşelem başarılı ve tamamlandı. Sayı: 7

Promise Rejected

Aşağıdaki kod bloğu, bir Promise oluşturarak içindeki asynchronous işlemi simüle eder. Ancak, bu kez işlem başarısız bir duruma yönlendirilmiştir. Belirli bir koşul sağlandığında, yani rastgele üretilen sayı 5'ten küçük olduğunda(ki kasıtlı olarak 5'e kadar üretecek), reject çağrısı yapılarak işlem başarısız hale getirilir. Bu durumu ele almak için, oluşturulan Promise nesnesinin catch metodunu kullanarak hatalı duruma tepki verir.

const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.floor(Math.random() * 5);
if (randomNumber < 5) {
reject("Error: İşlem başarısız! Sayı 5'ten küçük.");
}
}, 1000);
});

promise.catch(error => console.error(error));
// Error: İşlem başarısız! Sayı 5'ten küçük.

Promise Chaining (Zincirleme)

Promise Chaining, JavaScript’te birden çok asynchronous işlemi temiz ve organize bir şekilde sıraya koymanıza olanak tanıyan güçlü bir tekniktir. Bir promise’in çıktısını bir sonraki promise’in girdisi olarak işlemenizi sağlar, böylece birbirinin ardından çalışan bir promise chain oluşturursunuz. Bu yaklaşım, asynchronous programming basitleştirir ve karmaşık iş akışlarını yönetmeyi kolaylaştırır.

Birden çok promise’i birbirine bağlamayı ve bir promise’in çıktısının bir sonrakinin girdisi olmasını içerir. Bu, asynchronous taskleri sırayla ele almanıza ve bir promise’den diğerine veri aktarmanıza olanak tanır.

Aşağıdaki kod bloğu, asynchronous function kullanarak bir API’den kullanıcı verilerini almak için kullanıldı. Kod, fetch() işlemini kullanarak iki farklı URL'den veri çeker: birincisi tüm kullanıcıları içeren https://reqres.in/api/users, ikincisi ise belirli bir kullanıcının detaylarını içeren https://reqres.in/api/users/${id}. İlk olarak, fetchAllUsers() işleviyle tüm kullanıcıların listesini alır. Ardından, bu liste içerisinden ilk kullanıcının ID'sini çıkarır ve bu ID'yi kullanarak fetchUserById() işlemini çağırarak belirli kullanıcının detaylı bilgilerini alır. Son aşamada ise, elde edilen kullanıcı verilerini konsola yazdırarak işlemi tamamlar.

fetchAllUsers() function bir promise döndürür ve bu promise fulfilled olduğunda, then() metodu ile yanıttan kullanıcı verilerini alır ve bir başka promise döndürür. Bu zincirleme süreç, her bir then() bloğu içerisinde bir önceki işlemin çıktısını alıp, bir sonraki eşzamansız işlemi başlatma esnekliği sunar. Bu sayede kod, okunabilirlik ve yönetilebilirlik açısından avantajlar sağlar, birden çok eşzamansız işlemi tek bir adımda gerçekleştirir.

// Kullanıcı verilerini almak için API'ye istek gönderen işlev
const fetchAllUsers = () => fetch('https://reqres.in/api/users');

// Belirli bir kullanıcının detaylarını almak için API'ye istek gönderen işlev
const fetchUserById = (id) => fetch(`https://reqres.in/api/users/${id}`);

// Tüm kullanıcıları al ve ilk kullanıcının detaylarını yazdır
fetchAllUsers()
.then(response => response.json()) // API yanıtını JSON'a dönüştür
.then(users => fetchUserById(users.data[0].id)) // İlk kullanıcının ID'sini kullanarak belirli bir kullanıcının detaylarını al
.then(response => response.json()) // API yanıtını JSON'a dönüştür
.then(user => console.log(user.data)); // Alınan kullanıcı verilerinikonsola yazdır

Artıları:

  • Asenkron İşlemleri Yönetme: Promise’ler, özellikle asynchronous operasyonları daha etkili bir şekilde yönetmek için tasarlanmıştır. Bu, callback function kullanmaktan daha okunabilir ve yönetilebilir bir kod sağlar.
  • Daha Okunabilir ve Düzenli Kod: Promise chaining, ardışık işlemleri tek bir blokta ifade etmenizi sağlar. Bu, kodunuzu daha düzenli ve okunabilir kılar.
  • Error Handling Kolaylığı: Promise’ler, hata yönetimini kolaylaştırır. catch() metodunu kullanarak tüm zincir boyunca meydana gelebilecek hataları ele alabilirsiniz.
  • Birden Çok Asenkron İşlemi Koordine Etme: Promise’ler, birden çok asynchronous operasyon koordine etmeyi kolaylaştırır. Örneğin, bir dizi asynchronous operasyon sırayla veya paralel olarak gerçekleştirebilirsiniz.

Eksileri:

  • Gerçek Zamanlı Güncelleme Zorluğu: Promise’ler, bir kere başlatıldıktan sonra gerçek zamanlı olarak güncellenemez. Yani bir promise başladığında, içindeki değeri daha sonra değiştiremezsiniz.
  • Yatay Genişleme Zorluğu: Callback functionlarına benzer şekilde, promise chaining de çok fazla işlem eklediğinizde kodun yatay genişlemesini (horizontal expansion) zorlaştırabilir.
  • Esnek Olmama: Promise’ler, bir kez oluşturulduktan sonra temel yapısı itibariyle değişmezdir. Bu, onları daha esnek olmayan hale getirebilir.
  • Hata İzleme Zorluğu: Chaining içindeki bir hata, hangi adımda oluştuğunu tespit etmeyi zorlaştırabilir. Bu durumu ele almak için ekstra çaba sarf edilmesi gerekebilir.

Async/Await

Async/await, JavaScript’te asynchronous işlemleri daha anlaşılır ve düzenli bir şekilde ele almak için kullanılan modern bir programlama sözdizimidir. Bu yapı, geleneksel olarak kullanılan Callbacks ve Promises’e göre daha açık ve okunabilir bir kod yazma süreci sunar. Özellikle, karmaşık asenkron iş akışlarına sahip projelerde oldukça faydalıdır.

Async/await, JavaScript’te asynchronous işlemler için şu avantajları sunar:

  • Daha özlü: Async/await, asynchron kodu daha az yazarak ve daha az geliştirme hatası yaparak anlamanızı sağlar. Bu, kodunuzu daha hızlı yazmanıza ve daha hızlı anlamanıza yardımcı olur.
  • Daha yapılandırılmış: async/await, asynchronous kodu daha yapılandırılmış ve anlaşılması kolay bir şekilde yazmanıza olanak tanır. Bu, hata ayıklamaya ve kodun bakımını kolaylaştırmaya yardımcı olur.
  • Hatalarla daha kolay başa çıkma: async/await, hata ayıklamaya daha kolay ve verimli bir şekilde yardımcı olan hata işleme desteği sunar. Bu, özellikle karmaşık asynchronous işlemleri ele alırken önemlidir.

Callbacks ve Promises, JavaScript’te asynchronous işlemleri yönetmek için kullanılan geleneksel yaklaşımlardır. Callbacks, asynchronous işlemin tamamlanmasından sonra yürütülecek olan başka bir function’a bir function olarak geçirmeyi içerir. Promise’ler ise bir asynchronous işlemin nihai tamamlanmasını veya başarısızlığını temsil eder ve sonucu ele almak için then() ve catch() gibi yöntemler sağlar.

Async/await, bu iki yaklaşımın avantajlarını birleştirir. Callbacks ve Promises’in basitliğini ve okunabilirliğini promise’lerin hata işleme yetenekleri ile birleştirir.

Async function asynchronous işlemleri içerebilen functionlardır. async function içinde, bir asynchronous işlemin tamamlanmasını beklemeden önce await anahtar sözcüğünü kullanabilirsiniz.

Await function, bir Promise’in değerini döndürür. Bu, Promise’in çözülmesini ve değerinin alınmasını beklemek için kullanılır.

Şimdi, async functionları daha detaylı inceleyelim: Async functionlar, içerdikleri asynchron işlemleri daha yönetilebilir kılan functionlardır. İçlerinde await anahtar kelimesini kullanarak, belirli bir asynchron işlemin tamamlanmasını bekleyebilir ve bu işlemin sonucunu elde edebiliriz.

Örneğin, bir API’den veri çekme işlemiyle ilgili bir async function ele alalım:

async function fetchUsers() {
const res = await fetch('https://reqres.in/api/users');
const data = await res.json();
return data;
}

async function getAllUsers() {
const users = await fetchUsers();
return users.data;
}

getAllUsers()
.then(users => console.log(users))
.catch(err => console.log(err));
  1. fetchUsers() Function: Bu asynchronus function, https://reqres.in/api/users API uç noktasından tüm kullanıcıların bir listesini alır. API isteğini yapmak için fetch() işlevini ve yanıtı almadan önce beklemek için await anahtar sözcüğünü kullanır. Yanıt alındıktan sonra, JSON verilerini işler ve elde edilen kullanıcı bilgilerini döndürür.
  2. getAllUsers() Function: Bu asynchronus function, fetchUsers() işlevini çağırarak ve await anahtar sözcüğünü kullanarak tamamlanmasını bekleyerek tüm kullanıcıların listesini alır. Kullanıcı verileri kullanılabilir hale geldiğinde, yanıttan gerçek kullanıcı bilgilerini çıkarır ve döndürür.
  3. Promise Chaining: Kod, getAllUsers() işlevini çağırır ve sırasıyla yanıt verilerini ve olası hataları işlemek için then() ve catch() yöntemlerini zincirleme yapar. then() yöntemi, alınan kullanıcı verilerini konsola yazarken, catch() yöntemi işlem sırasında meydana gelen herhangi bir hatayı yazar.

Artıları:

  • Daha Okunabilir Kod: Async/Await, Promise Chaining’i daha okunabilir ve anlaşılır hale getiren await ifadesi kullanır. Bu, karmaşık asynchron kodları daha düzenli ve akışkan bir şekilde yazmanıza olanak tanır.
  • Hata İzleme ve İşleme: Try-Catch blokları kullanarak hata yönetimi Async/Await ile daha etkili bir şekilde gerçekleştirilebilir. Bu, hataların daha iyi izlenmesini ve işlenmesini sağlar.
  • Synchronous Tarzında Kod Yazma: Async/Await, asynchron kodu sanki synchron gibi yazmanıza olanak tanır. Bu, geleneksel synchronus programming’e daha yakın bir yazım tarzı sunar.

Eksileri:

  • Döngüsel Bekleme: Async funtionlar içinde kullanılan await ifadesi, birçok durumda döngüsel bekleme nedeniyle performans sorunlarına yol açabilir. Bu, işlemlerin sırayla tamamlanmasına neden olabilir.
  • Promiselerin Gerekli Olması: Async/Await, alt seviyede hala Promise’leri kullanır. Bu nedenle, Promise’lerle ilgili olası sorunlar (örneğin, rejection durumları) hala dikkate alınmalıdır.
  • Error Handling Zorlukları: Async funtionlarda birden çok Promise Chain olduğunda hata yönetimi karmaşık hale gelebilir. Her bir asynchron çağrı için ayrı ayrı hata işleme eklemek, kodu gereksiz yere şişirebilir.

Buraya kadar okuduğunuz için teşekkür ederim. Olabildiğince bir çok konuya değinmek istedim ve umarım sizin ilginizi çekmiştir. Bir sonraki yazımda görüşmek dileğiyle :).

--

--