
JavaScript'te Asenkron Programlama: Callbacks, Promises ve Async/Await
JavaScript, özellikle web geliştirme alanında oldukça popüler bir dil. Modern web uygulamaları, hızlı ve dinamik kullanıcı deneyimleri sunabilmek için sıklıkla asenkron işlemler kullanır. Asenkron programlama, programın belirli bir işlemi yaparken ana işleyişi engellemeden devam etmesine olanak tanır. Bu yazıda, JavaScript’te asenkron programlamayı anlamanızı sağlayacak temel kavramları, yöntemleri ve örneklerle birlikte açıklayacağız: Callbacks, Promises ve Async/Await.
1. Asenkron Programlama Nedir?
Asenkron programlama, kodun bir kısmının çalışırken diğer kısmının beklemeden çalışmaya devam etmesini sağlar. Örneğin, bir web API'sine istek gönderdiğinizde, istek sonucu gelene kadar uygulamanız donmaz. Bu, özellikle zaman alıcı işlemlerde (veri çekme, dosya okuma, API çağrıları gibi) önemlidir.
Asenkron İşlemin Çalışma Prensibi
Asenkron işlemler, işlemi başlatan kısımla sonuç almayı bekleyen kısımlar arasında zaman farkı olduğunda kullanılır. Örneğin:
- Kullanıcı veritabanına istek gönderir.
- Bu işlem başlatılır ancak sonuç hemen gelmez.
- Kullanıcı arayüzü diğer işlemleri gerçekleştirmeye devam eder.
- Sonuç geldiğinde, işleme özel bir callback fonksiyonu çalıştırılır.
JavaScript'te asenkron programlama yapabilmek için kullanılan üç ana yöntem vardır: Callbacks, Promises ve Async/Await.
2. Callbacks (Geri Çağırma Fonksiyonları)
Callback, başka bir fonksiyonun parametresi olarak geçirilen bir fonksiyondur ve genellikle bir işlem tamamlandığında çağrılır. Callbacks, asenkron işlemlerle sonuç almayı sağlar. Ancak, karmaşık uygulamalarda "callback hell" ya da "callback pyramid" olarak bilinen durumlar ortaya çıkabilir. Bu, birçok callback fonksiyonunun iç içe geçirilmesinden kaynaklanır ve kodun okunabilirliğini zorlaştırabilir.
Callback Örneği
// Veritabanından veri çekmek için asenkron bir fonksiyon
function getUserData(userId, callback) {
setTimeout(() => {
const userData = { id: userId, name: 'Ali' };
callback(userData); // Callback fonksiyonu çağrılıyor
}, 2000);
}
// Kullanıcı verilerini alırken callback fonksiyonu kullanılıyor
getUserData(1, function(data) {
console.log(data); // { id: 1, name: 'Ali' }
});
Yukarıdaki örnekte, getUserData
fonksiyonu 2 saniye süren bir işlemi simüle eder. İşlem tamamlandığında callback
fonksiyonu çağrılır ve veriler kullanıcıya gösterilir.
Callback Hell
getUserData(1, function(data1) {
getUserData(2, function(data2) {
getUserData(3, function(data3) {
console.log(data1, data2, data3);
});
});
});
Yukarıdaki örnekte, callback'lerin birbirine iç içe geçirilmesi, kodun karmaşık ve okunabilirliğini zorlaştırır. Bu sorunları aşmak için Promises ve Async/Await kullanılır.
3. Promises (Sözler)
Promises, callback'lere bir alternatif olarak ortaya çıkmıştır. Bir promise, gelecekte tamamlanacak bir asenkron işlemi temsil eder. Promise, ya başarılı bir şekilde sonuçlanır (resolve) ya da bir hata ile sonlanır (reject). Promises, callback hell'in önüne geçmek için daha temiz ve anlaşılır bir yapı sunar.
Promise Yapısı
let myPromise = new Promise(function(resolve, reject) {
let success = true;
if (success) {
resolve("İşlem başarılı!");
} else {
reject("İşlem başarısız.");
}
});
Promise, üç farklı durumda olabilir:
- Pending (Beklemede): Henüz tamamlanmamış bir işlem.
- Fulfilled (Tamamlanmış): İşlem başarılı bir şekilde tamamlanmış.
- Rejected (Reddedilmiş): İşlem başarısız olmuş.
Promise Kullanımı
function getUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const userData = { id: userId, name: 'Ali' };
resolve(userData); // İşlem başarılı
}, 2000);
});
}
getUserData(1)
.then((data) => {
console.log(data); // { id: 1, name: 'Ali' }
})
.catch((error) => {
console.log(error); // Hata varsa burada işlenir
});
Yukarıdaki örnekte, getUserData
fonksiyonu bir Promise döner. Bu Promise, işlem başarılı olursa .then()
bloğunda, başarısız olursa .catch()
bloğunda işlenir. Bu, kodun daha okunabilir ve yönetilebilir olmasını sağlar.
Promise Chaining
Promises ile, bir dizi asenkron işlem zincirleme (chaining) olarak yapılabilir. Her .then()
bloğu bir önceki Promise’in sonucunu alır.
getUserData(1)
.then((data) => {
console.log(data); // { id: 1, name: 'Ali' }
return getUserData(2); // Yeni Promise döndürüyoruz
})
.then((data) => {
console.log(data); // { id: 2, name: 'Ayşe' }
})
.catch((error) => {
console.log(error);
});
4. Async/Await (Asenkron Bekleme)
Async/Await, Promises ile yazılmış asenkron kodları daha da okunabilir hale getiren bir JavaScript özelliğidir. async
fonksiyonu, her zaman bir Promise döner. await
ise, bir Promise’in çözülmesini bekler.
Async/Await Kullanımı
async function getUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const userData = { id: userId, name: 'Ali' };
resolve(userData);
}, 2000);
});
}
async function displayUserData() {
try {
const data = await getUserData(1); // Promise tamamlanana kadar bekler
console.log(data); // { id: 1, name: 'Ali' }
} catch (error) {
console.log(error); // Hata durumunda
}
}
displayUserData();
Yukarıdaki örnekte, getUserData
fonksiyonu bir Promise dönerken, displayUserData
fonksiyonu async
olarak tanımlanmıştır. await
, Promise’in sonuçlanmasını bekler. Böylece kod daha okunabilir hale gelir.
Async/Await ile Promise Chaining
Async/Await ile Promise chaining çok daha temiz bir şekilde yazılabilir.
async function displayUserData() {
try {
const user1 = await getUserData(1);
console.log(user1); // { id: 1, name: 'Ali' }
const user2 = await getUserData(2);
console.log(user2); // { id: 2, name: 'Ayşe' }
} catch (error) {
console.log(error);
}
}
displayUserData();
Async/Await, asenkron kod yazmayı daha senkron (eşzamanlı) bir hale getirir ve karmaşıklığı azaltır.
5. Hangi Durumda Ne Kullanılır?
- Callback: Küçük, basit işlemler için uygundur. Ancak, karmaşık uygulamalarda callback hell'e yol açabilir.
- Promises: Callback'lerin yerine kullanılabilir. Kodun okunabilirliğini artırır ve hata yönetimini kolaylaştırır.
- Async/Await: Promise yapısının daha temiz ve okunabilir bir şekilde yazılmasını sağlar. Çoğu modern JavaScript projesinde önerilen yöntemdir.
Sonuç
JavaScript'te asenkron programlama, dinamik ve hızlı uygulamalar geliştirmenin temel taşlarından biridir. Callbacks, Promises ve Async/Await; her biri farklı avantajlar sunarak asenkron işlemleri daha yönetilebilir hale getirir. Callbacks, temel asenkron işlemler için uygundur, ancak karmaşık senaryolarda yerini Promises ve Async/Await'e bırakır. Async/Await, özellikle modern projelerde kodu daha anlaşılır ve yönetilebilir hale getirir.
Her üç yöntemi de doğru şekilde kullanarak, asenkron işlemlerle daha verimli çalışabilir ve daha sağlam uygulamalar geliştirebilirsiniz.
Yorum Yap