- Konu sahibi
- #1
JavaScript callback, başka bir fonksiyona parametre olarak verilen ve alan kod tarafından uygun anda çağrılan fonksiyondur. Çağrı aynı işlem sırasında eşzamanlı veya daha sonra asenkron gerçekleşebilir. Böylece bir işlem sonucunu, işlem bitince ne yapılacağını belirleyen koddan ayırabilirsiniz. Callback özellikle olay dinleyicilerinde, zamanlayıcılarda ve tamamlanması daha sonra gerçekleşen asenkron işlemlerde kullanılır.
JavaScript'te fonksiyonlar birer değer gibi kullanılabilir. Bir fonksiyonu parantezlerini eklemeden başka bir fonksiyona verirseniz, onu hemen çalıştırmak yerine referansını aktarırsınız. Alan fonksiyon, uygun zamanda callback'i çağırır.
Bu örnekte
Callback'in önemli kullanım alanlarından biri, işlemin hemen tamamlanmadığı durumlardır.
Beklenen çıktı sırası şöyledir:
Çünkü
Asenkron bir işlem hem hata hem de sonuç üretebilir. Özellikle Node.js API’lerinde yaygın bir yaklaşım, callback'in ilk parametresini hataya ayırmaktır:
Burada ilk değer
Callback kullanımı, işlemin tamamlanma davranışını dışarıdan belirlemek istediğinizde uygundur. Ancak aynı işlem içinde çok sayıda iç içe callback kullanmak okunabilirliği azaltabilir. Karar verirken şu ayrımı kullanın:
Callback, Promise'in alternatifi olmak zorunda değildir; bir Promise tabanlı API'nin içinde olay veya düşük seviyeli bir işlem için yine kullanılabilir. Sorun genellikle callback'in kendisi değil, hata yönetiminin dağınık olması ve işlemlerin gereksiz şekilde iç içe yazılmasıdır.
Callback nasıl çalışır?
JavaScript'te fonksiyonlar birer değer gibi kullanılabilir. Bir fonksiyonu parantezlerini eklemeden başka bir fonksiyona verirseniz, onu hemen çalıştırmak yerine referansını aktarırsınız. Alan fonksiyon, uygun zamanda callback'i çağırır.
Kod:
function islemiYap(veri, tamamlaninca) {
const sonuc = veri * 2;
tamamlaninca(sonuc);
}
function sonucuGoster(deger) {
console.log("Sonuç:", deger);
}
islemiYap(5, sonucuGoster);
Bu örnekte
sonucuGoster fonksiyonu callback'tir. islemiYap hesaplamayı yapar ve sonucu callback'e gönderir. Çıktı şöyle olur:
Kod:
Sonuç: 10
islemiYap(5, sonucuGoster) yazımı doğrudur. islemiYap(5, sonucuGoster()) ise farklıdır; sonucuGoster() çağrıyı hemen çalıştırır ve çoğu durumda undefined aktarır.Asenkron callback örneği
Callback'in önemli kullanım alanlarından biri, işlemin hemen tamamlanmadığı durumlardır.
setTimeout örneğinde callback, verilen gecikmeden önce çalıştırılmayacak biçimde zamanlanır; tam o milisaniyede çalışması garanti değildir:
Kod:
console.log("Başladı");
setTimeout(function () {
console.log("Bekleme tamamlandı");
}, 100);
console.log("Devam etti");
Beklenen çıktı sırası şöyledir:
Kod:
Başladı
Devam etti
Bekleme tamamlandı
Çünkü
setTimeout bekleme sırasında JavaScript'in devam eden kodu çalıştırmasını engellemez. Süre dolunca callback çalışma sırasına alınır. Bu nedenle callback içindeki sonucu, callback'in dışındaki kodda hemen kullanılabilir varsaymamalısınız.Hata ve sonuç taşıyan callback tasarımı
Asenkron bir işlem hem hata hem de sonuç üretebilir. Özellikle Node.js API’lerinde yaygın bir yaklaşım, callback'in ilk parametresini hataya ayırmaktır:
Kod:
function kullaniciGetir(basarili, callback) {
setTimeout(function () {
if (!basarili) {
callback(new Error("Kullanıcı alınamadı"));
return;
}
callback(null, { id: 1, ad: "Ada" });
}, 50);
}
kullaniciGetir(true, function (hata, kullanici) {
if (hata) {
console.error(hata.message);
return;
}
console.log(kullanici.ad);
});
Burada ilk değer
null ise işlem başarılı kabul edilir ve ikinci değer kullanılır. Hata oluştuğunda return ile devam eden kodun çalışması engellenir. Örneği false ile çalıştırırsanız Kullanıcı alınamadı mesajını görürsünüz; bu, callback sözleşmesine göre hata yolunun çalıştığını gösterir.Callback ne zaman tercih edilir?
Callback kullanımı, işlemin tamamlanma davranışını dışarıdan belirlemek istediğinizde uygundur. Ancak aynı işlem içinde çok sayıda iç içe callback kullanmak okunabilirliği azaltabilir. Karar verirken şu ayrımı kullanın:
| İhtiyaç | Uygun yaklaşım | Neden |
|---|---|---|
| Bir olay olduğunda kod çalıştırmak | Callback | Olay dinleyicisi çağrılacak işlevi alır |
| Basit ve kısa gecikmeli işlem | Callback | Ek soyutlama gerektirmez |
| Birden çok asenkron adımı sıraya koymak | Promise veya async/await | İç içe yapıyı azaltır |
| İşlemden doğrudan değer döndürmek | return | Sonuç aynı çağrı akışında hazırdır |
Callback, Promise'in alternatifi olmak zorunda değildir; bir Promise tabanlı API'nin içinde olay veya düşük seviyeli bir işlem için yine kullanılabilir. Sorun genellikle callback'in kendisi değil, hata yönetiminin dağınık olması ve işlemlerin gereksiz şekilde iç içe yazılmasıdır.
Sık yapılan hatalar
- Callback'i hemen çalıştırmak:
setTimeout(islemiYap(), 100)yerinesetTimeout(islemiYap, 100)veya parametre gerekiyorsasetTimeout(() => islemiYap(veri), 100)kullanın. - Asenkron sonucu dışarıda beklemek: Callback daha sonra çalışacağı için callback içindeki sonucu dışarıdaki
returnile döndürmeye çalışmayın. - Hata yolunu kontrol etmemek: Hata parametresi varsa önce onu denetleyin; hata varken sonuç nesnesini kullanmak yeni bir hataya yol açabilir.
- Tek sonuçlu işlem callback’ini iki kez çağırmak: Bu örnekte başarı ve hata yollarından yalnızca biri sonuç vermelidir. Olay dinleyicileri gibi tekrar çağrılmak üzere tasarlanan callback’lerde ise çoklu çağrı normaldir.