Bvural41 1
Bvural41
emirhanHCL 1
emirhanHCL
kralhakan2009 1
kralhakan2009
Vahsi Uzman 1
Vahsi Uzman
Hikaye Ekle

[NODE JS] Promise Chaining ile Zincirleme Islemler

Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!

nodejs.png


[NODE JS] Promise Chaining ile Zincirleme Islemler​


Herkese merhaba, bugun Promise chaining yani Promise zincirleme konusunu detayli inceleyecegiz. Bir onceki yazida Promise'in ne oldugunu ogrendik, simdi gercek gucunu gosterme zamani. Promise chaining, birbirine bagli asenkron islemleri sirayla calistirmanin en temiz yoludur ve callback hell'e karsi en etkili silahtir.

Chaining Nasil Calisir?​


Promise chaining'in temeli su kurala dayanir: then() metodu her zaman yeni bir Promise dondurur. Bu sayede then'leri arka arkaya zincirleyebilirsiniz. Her then'in callback fonksiyonundan dondurdugunuz deger, bir sonraki then'in parametresi olur. Eger then'den bir Promise dondururseniz, sonraki then o Promise resolve olana kadar bekler. Bu mekanizma sayesinde asenkron islemleri senkronmus gibi sirayla calistirabilirsiniz.

Ben bu mekanizmayi ilk anladigimda kafa da bir ampul yandi gercekten. Callback hell'de 10 seviye ic ice yazmak yerine, duz bir zincir halinde yazabilmek muhtesamdi. Kod okunakli, hata yonetimi merkezi ve her adim kendi sorumluluk alaninda.

JavaScript:
// Temel chaining
const fs = require('fs/promises');

// Her then yeni bir Promise dondurur
Promise.resolve(1)
    .then(deger => {
        console.log('Adim 1:', deger); // 1
        return deger + 10;
    })
    .then(deger => {
        console.log('Adim 2:', deger); // 11
        return deger * 2;
    })
    .then(deger => {
        console.log('Adim 3:', deger); // 22
        return deger.toString();
    })
    .then(deger => {
        console.log('Adim 4:', deger); // "22" (string)
        console.log('Tipi:', typeof deger);
    });

// Asenkron islemlerle chaining
function bekle(ms, deger) {
    return new Promise(resolve => {
        setTimeout(() => resolve(deger), ms);
    });
}

bekle(100, 'merhaba')
    .then(mesaj => {
        console.log('1:', mesaj);
        return bekle(100, mesaj + ' dunya');
    })
    .then(mesaj => {
        console.log('2:', mesaj);
        return bekle(100, mesaj + '!');
    })
    .then(mesaj => {
        console.log('3:', mesaj); // "merhaba dunya!"
    });

Gercek Dunya Ornegi: API Pipeline​


Simdi gercek bir senaryoya bakalim. Bir e-ticaret sitesinde siparis olusturma akisini dusunun: once kullaniciyi dogrula, sonra stok kontrol et, sonra odemeyi isle, sonra siparisi kaydet ve son olarak bildirim gonder. Her adim bir oncekinin sonucuna bagli. Bu tam olarak Promise chaining icin ideal bir senaryo.

JavaScript:
// E-ticaret siparis akisi - Promise chaining ile
function kullaniciDogrula(token) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (token === 'gecerli-token') {
                resolve({ id: 1, ad: 'Ahmet', bakiye: 5000 });
            } else {
                reject(new Error('Gecersiz token'));
            }
        }, 100);
    });
}

function stokKontrol(urunId, miktar) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const stoklar = { 'U001': 50, 'U002': 0, 'U003': 10 };
            const mevcutStok = stoklar[urunId] || 0;

            if (mevcutStok >= miktar) {
                resolve({ urunId, miktar, birimFiyat: 250 });
            } else {
                reject(new Error(`Yetersiz stok: ${urunId} (${mevcutStok} adet kaldi)`));
            }
        }, 100);
    });
}

function odemeIsle(kullanici, tutar) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (kullanici.bakiye >= tutar) {
                resolve({
                    islemId: 'PAY-' + Date.now(),
                    tutar,
                    durum: 'basarili'
                });
            } else {
                reject(new Error(`Yetersiz bakiye: ${kullanici.bakiye} TL (Gereken: ${tutar} TL)`));
            }
        }, 150);
    });
}

function siparisKaydet(siparisBilgi) {
    return new Promise((resolve) => {
        setTimeout(() => {
            const siparisId = 'SIP-' + Date.now();
            resolve({ ...siparisBilgi, siparisId, tarih: new Date().toISOString() });
        }, 100);
    });
}

function bildirimGonder(siparis) {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(`  Bildirim gonderildi: Siparis #${siparis.siparisId}`);
            resolve(siparis);
        }, 50);
    });
}

// Tum akisi chaining ile yazalim
console.log('Siparis akisi baslatiliyor...\n');

kullaniciDogrula('gecerli-token')
    .then(kullanici => {
        console.log(`  Kullanici dogrulandi: ${kullanici.ad}`);
        // Sonraki adima hem kullaniciyi hem stok bilgisini tasimamiz lazim
        return stokKontrol('U001', 2).then(stok => ({ kullanici, stok }));
    })
    .then(({ kullanici, stok }) => {
        const toplamTutar = stok.miktar * stok.birimFiyat;
        console.log(`  Stok uygun, toplam: ${toplamTutar} TL`);
        return odemeIsle(kullanici, toplamTutar)
            .then(odeme => ({ kullanici, stok, odeme }));
    })
    .then(({ kullanici, stok, odeme }) => {
        console.log(`  Odeme basarili: ${odeme.islemId}`);
        return siparisKaydet({
            kullaniciId: kullanici.id,
            urunId: stok.urunId,
            miktar: stok.miktar,
            odemeId: odeme.islemId,
            tutar: odeme.tutar
        });
    })
    .then(siparis => {
        console.log(`  Siparis kaydedildi: ${siparis.siparisId}`);
        return bildirimGonder(siparis);
    })
    .then(siparis => {
        console.log(`\nSiparis tamamlandi!`);
        console.log(JSON.stringify(siparis, null, 2));
    })
    .catch(hata => {
        // Zincirdeki HER HANGI bir adimda olusan hata buraya duser
        console.error(`\nSiparis hatasi: ${hata.message}`);
    })
    .finally(() => {
        console.log('\nIslem sonlandi (basarili veya basarisiz)');
    });

Chaining'de Sik Yapilan Hatalar​


En buyuk hata, then icinde return kullanmayi unutmaktir. Eger return kullanmazsaniz, sonraki then'e undefined gelir ve zincir kirilir. Bu hata sessizdir, hicbir hata mesaji vermez ama sonuc yanlis olur. Ben bu hataya o kadar cok dustum ki artik her then icinde return olup olmadigini ilk kontrol ettigim sey haline geldi.

Diger onemli hata, catch'i zincirin ortasina koymaktir. Catch koydugunuz yer onelidir cunku catch bir hatayi yakalayip handle ettikten sonra zincir devam eder. Catch'in kendisi de bir Promise dondurur. Eger catch'ten bir deger dondururseniz, sonraki then o degeri alir. Yani catch aslinda bir recovery mekanizmasidir.

Son olarak, Promise chaining guzel olsa da cok uzun zincirler okunaklilik sorununa yol acar. 5-6 then'den fazla zincirlemeniz gerekiyorsa, async/await'e gecmeyi dusunun. Zaten async/await promise chaining'in syntactic sugar'i, yani ustune serpilmis seker gibi daha tatli hali. Sonraki konularda Promise.all ve diger Promise metodlarini inceleyecegiz!
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst