Merhaba,


Bu yazıda Angular'da callback fonksiyonlar ve promise kullanımından bahsedeceğim. Bildiğiniz üzere diğer dillerden farklı olarak JavaScript asenkron çalışan bir programlama dilidir. Bu yüzden bir fonksiyondaki işlemlerin bitmesi beklenmeden diğer fonksiyona geçiş yapılır. Bizde işlemlerimizi sırayla yaptırmak için callback fonksiyonlardan veya promise'lerden yararlanırız.


Callback fonksiyonlarda, fonksiyona bir parametre olarak fonksiyonu gönderiyoruz ve çalışmasını istediğimiz yerde bunu çağırıyoruz. Ancak callback fonksiyonlarda beklenenden erken çağırılma gibi sorunlar çıkabiliyor. O yüzden bu yazıda callback fonksiyonların üstüne durmayacağız, bunun yerine daha güzeli Promise yapısından bahsedeceğiz.


Promise'ler yapması gereken işi yaptıktan sonra başarılı (resolved) veya başarısız (rejected) olur. Beklenmeyen hatalarda rejected sonucuna düşer ve hata yönetimi konusunda daha iyidir.


Şimdi bir örnek yapalım ve bu konuyu daha iyi anlayalım;

İlk önce promise kullanmadan çok basit bir örnek yapalım ve "JavaScript asenkron çalışan bir programlama dilidir" ne demekmiş, ne oluyormuş asenkron çalışınca bunu öğrenelim;


Bunu test etmek için bir Angular projesi oluşturalım veya stackblitz üzerinden bir proje oluşturalım, componentimiz içinde 3 tane fonksiyon oluşturalım, bunların içerisinde de konsola 1, 2, 3 şeklinde veri yazdıralım.. Daha sonra bu fonksiyonları sırasıyla ngOnInit() içerisinde çağıralım. Yani;

ngOnInit() {
  this.fonksiyon1();
  this.fonksiyon2();
  this.fonksiyon3();
}


fonksiyon1() {
  console.log(1);
}


fonksiyon2() {
  console.log(2);
}


fonksiyon3() {
  console.log(3);
}

Bunun çıktısıda aynen şu şekildedir;

1
2
3


Evet herhangi bir sıkıntı yok. Şimdi varsayalım ki fonksiyon2() içerisindeki işlemler 2 saniye sürsün, yani şu şekilde değiştirelim;

fonksiyon2() {
  setTimeout(() => {
    console.log(2);
  }, 2000);
}

Çıktıya birde şimdi bakalım;

1
3
2


Evet işte asenkron çalışma tam olarak budur. Biz fonksiyonlarımızı fonksiyon1() fonksiyon2() ve fonksiyon3()'ü sırasıyla çağırdık fonksiyon1 çalıştı, fonksiyon2 çalıştı bunun bitmesini beklemeden fonksiyon3 çalıştı.


İşlemleri sırayla yapmamız gerektiğinde ve böyle bir durumla karşılaştığımızda çarşı karışır.


Şimdi promise kullanalım ve fonksiyonlarımızı sırayla çalıştıralım.


Promise yazım şekli en basit haliyle aşağıdaki gibidir;

this.testFonksiyon()
  .then(res => {
    console.log(res); // başarılıysa çalışacak olan bölüm
  })
  .catch(err => {
    console.log(err); // başarısızsa çalışacak olan bölüm
  });

testFonksiyon() {
  return new Promise((resolve, reject) => {
    if ('işlemlerimiz başarılıysa') {
      resolve('başarılı');
    } else {
      reject('başarısız');
    }
  });
}


Şimdi ilk yaptığımız örneğimizi promise yapısına çevirelim.

ngOnInit() {
  this.fonksiyon1().then(res => {
    this.fonksiyon2().then(res => {
      this.fonksiyon3().then(res => {
        console.log('bütün işlemler tamam...');
      })
    })
  }).catch(err => {
    console.log('hata');
  })
}


fonksiyon1() {
  return new Promise((resolve, reject) => {
    console.log(1);
    resolve();
  });
}


fonksiyon2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(2);
      resolve();
    }, 2000);
  });
}


fonksiyon3() {
  return new Promise((resolve, reject) => {
    console.log(3);
    resolve();
  });
}

Şuan çalışan kodlarımızın çıktısına bir bakalım;

1
2
3
bütün işlemler tamam...

Evet fonksiyonlarımızı sırayla çalıştırdık. Yani istediğimiz sonuca ulaştık.


Örneğin fonksiyon2() içerisinde işlemlerimiz hatalı olsaydı yani reject() olsaydı çıktımız nasıl olurdu;

1
2
ERROR

Hataya düştüğü yerde catch() bloğuna girer ve devam etmez.


Şimdi burda bilmemiz gereken birkaç nokta var;

  • Promise'leri bir değişkene atayabiliriz.
  • Promiseler kodlarımızı satır satır çalıştırmaz. Promise'ler, birden fazla asenkron işlemlerin sırayla gerçekleştirilmesi içindir.
  • Birden fazla .then() arka arkaya eklenebilir. .then() içerisinde çalışacak fonksiyonu return ettirip bir sonraki .then() içerisine aktarılır.
  • Hataları yakalamak için her .then() sorasına .catch() eklenmesine gerek yoktur. 1 tane .catch() yeterlidir. Sıralı işlemler ne zaman hataya düşerse bu .catch() bloğuna girecektir.


Buraya kadar her şey tamam. Peki bizim örneğimizde 3 fonksiyon vardı sıkıntı çekmedik ama 10 fonksiyon olsaydı kodlarımız yana doğru uzayıp gidecekti (aduket gibi bir görüntü olacaktı).


Şimdi yukarıdaki ngOnInit() içerisindeki kodlarımızı tekrar yazalım;

this.fonksiyon1().then(res => {
  return this.fonksiyon2();
}).then(res => {
  return this.fonksiyon3();
}).then(res => {
  console.log('bütün işlemler tamam...');
}).catch(err => {
  console.log('hata');
})

Evet, artık kodlarımız aduket gibi uzayıp gitmeyecek. Bu kullanım daha güzel sanki.


Yazdıklarımızı incelemek isterseniz: https://stackblitz.com/edit/kb-angular-promise

Umarım faydalı olur.