Express.js ile Mongoose Kullanarak Async Programlamaya Örnek Verelim

Merhaba,

Öncelikle bu yazıyı anlayabilmeniz için node.js temellerine hakim olmanız, express.js rounting işlemlerinin nasıl yönetildiğini biliyor olmanız ve mongoose orm kütüphanesini projenize eklemiş olmanız gerekmektedir 🙂

Bir senaryo düşünelim hemen. Son kullanıcıdan bilgi topladığınız bir form geliştirdiniz. Bu form’a mongodb’nizin 2 farklı collection’ından verileri çekip sayfada görüntülemeniz gerekiyor. Bu collection’ların isimleri de kategoriler (ürünün listeleneceği kategori) ve gecerliUlkeler (satış yapılabilecek ülkeler) olsun



Nasıl yaparsınız?

1- Kötü Yöntem: inception

Her bir sorgunun callback function’unun içerisine diğer sorguyu yazarak çektiğiniz objeleri sayfaya return edebilirsiniz. Ancak bu yöntem, 2 collection için değil de 20 collection’ın return edilmesi için kullanılsaydı kodunuz okunamaz hale gelecekti.

// ürün ekleme sayfası url'i /urun/ekle olsun.
router.get('/urun/ekle', (req, res) => {
    kategoriler.find({})
        .sort({created_date: 'desc'})
        .then(kategoriListesi => {
             gecerliUlkeler.find({})
                 .sort({created_date: 'desc'})
                 .then(ulkeler => {
                    res.render('product/add', {
                        kategoriler: kategoriListesi,
                        ulkeler: ulkeler
                    });
             });
        });
});

Gördüğünüz gibi iç içe iki farklı find query ile çektiğimiz sonuçları product/add sayfasına return ettik.

Ancak dediğimiz gibi bu yöntem, 20 farklı collection’dan çektiğiniz verileri return etmek istediğinizde router’ınızı okunması güç bir kod bloğu haline getirecektir.

2- Doğru Yöntem: async

Öncelikle projenizin bulunduğu dizini komut satırında açıp aşağıdaki komut ile async kütüphanesini indirin.

Async hakkında daha detaylı bilgi almak için https://caolan.github.io/async/ sayfasını ziyaret edebilirsiniz.

npm install --save async

Artık async kodumuzu yazabiliriz.

// ürün ekleme sayfası url'i /urun/ekle olsun.
router.get('/urun/ekle', (req, res) => {
    var queries = []; // her sorguyu queries dizisine push edeceğiz

    // kategorileri çektik ve bir array'e push ettik
    queries.push(function (cb) {
        Categories.find({})
            .sort({created_date: 'desc'})
            .then(results => {
                cb(null, results);
            });
    });

    // gecerliUlkeler'i çektik ve bir array'e push ettik
    queries.push(function (cb) {
        gecerliUlkeler.find({})
            .sort({created_date: 'desc'})
            .then(results => {
                cb(null, results);
            });
    });

   /***** 
   * async.parallel() içerisine queries dizimizi ekledik.
   * parallel fonksiyonu bizim için queries dizisindeki tüm
   * sorguları eş zamanlı çalıştırdı ve her bir sonucu docs
   * isimli bir diziye ekledi. Biz de docs dizisinden ihtiyacımız
   * olan değerleri aşağıdaki gibi okuyup ürün ekleme sayfamızı bu 
   * verilerle render ettik.
   *****/ 
    async.parallel(queries, function (err, docs) {
        if (err) throw err;
        res.render('product/add', {
            kategoriler: docs[0],
            ulkeler: docs[1]
        });

    });
});

Tabi büyük projelerde bu tür işlemleri router’da yapmak yerine servis katmanında yapmanızı öneririz.

Ancak küçük çaplı projelerde sorun olacağını düşünmüyoruz.

Hepinize iyi çalışmalar dileriz.

Tüm soru ve görüşleriniz için tıklayınız.