मेरे पास एक साधारण है

var express = require('express')

नोड एक्सप्रेस www पृष्ठ, हमेशा की तरह सत्र, पग आदि का उपयोग करते हुए। मेरा डीबी कॉल

var db = require('./scripts/myHappyMysqlScript')

मैं स्वाभाविक रूप से mysql का उपयोग कर रहा हूं, इसलिए डीबी स्क्रिप्ट में

var mysql = require('mysql')

तो उदाहरण के लिए

app.get('/catPhotos', (req, response) => {
    response.render('catPhotos.pug');
})

मान लें कि किसी पृष्ठ में petNames डेटाबेस से कुछ दिखाने वाली तालिका है,

app.get('/pets', function(req, res, next) {
    db.allPetNames(function(err, petsList) {
        res.render('pets.pug',
            {
                'petsList': petsList,
                'pretty' : true
            })
    })

अब तक सब अच्छा।

लेकिन यहां एक मामला है जिसमें पग पेज पर तीन टेबल और तीन अलग-अलग डेटाबेस कॉल हैं:

db.cats(function(err, c) {
    db.dogs(function(err, d) {
        db.budgies(function(err, b) {
            res.render('bigScreen.pug',
                {
                    'cats' : c,
                    'k9s': d,
                    'budgies': b,
                    'pretty' : true
                })
        })
    })
})

मैं उन्हें ऐसे ही घोंसला बनाता हूं।

ऐसा लगता है कि यह पूरी तरह से काम करता है।

यह क्रमिक रूप से सही ढंग से प्रतीक्षा करता है। त्रुटियां आती हैं और ठीक से संभाली जाती हैं, और इसी तरह।

लेकिन क्या कोई बेहतर वाक्यविन्यास है, बेहतर तरीका है? वास्तविक ™ नोड के लिए नोड तरीका क्या है, स्विफ्ट नहीं, प्रोग्रामर ?!

शायद यह देखते हुए कि मैं mysql पुस्तकालय का उपयोग कर रहा हूं, यदि यह प्रासंगिक है।


ध्यान दें, कुल मिलाकर एक बेहतर तरीका यह है कि वेब पेज के प्रत्येक "भाग" में स्ट्रीम करने के लिए अजाक्स जैसी किसी चीज़ का उपयोग किया जाए। वास्तव में मैं हर समय ऐसा करता हूं। मैं यहाँ क्या पूछ रहा हूँ, res.render पर यह मानते हुए कि मैं वास्तव में एक ही बार में वह सारी जानकारी वापस करना चाहता हूँ, क्या इस तरह नेस्टिंग से बेहतर कुछ है? चीयर्स

5
Fattie 21 अक्टूबर 2020, 16:26

5 जवाब

सबसे बढ़िया उत्तर

promises.

चूंकि आपने उल्लेख किया है कि आप डेटाबेस के साथ इंटरैक्ट करने के लिए mysql लाइब्रेरी का उपयोग कर रहे हैं, दुर्भाग्य से, यह पुस्तकालय वादा-आधारित एपीआई प्रदान नहीं करता है। तो अपने कोड में नेस्टेड डेटाबेस कॉल से छुटकारा पाने के लिए, आपको डेटाबेस कॉल के कॉलबैक संस्करण के आसपास एक वादा-आधारित रैपर बनाने की आवश्यकता है।

वादे क्या हैं और वे कैसे काम करते हैं, इसके सामान्य अवलोकन के लिए, निम्नलिखित लिंक देखें:

निम्नलिखित एक उदाहरण है कि आप एक वादा-आधारित रैपर कैसे बना सकते हैं और फिर उस रैपर का उपयोग नेस्टेड डेटाबेस कॉल से छुटकारा पाने के लिए कर सकते हैं।

यह वादा-आधारित आवरण केवल एक फ़ंक्शन है जो एक वादा लौटाता है। यह एक वादा उदाहरण बनाता है, अंतर्निहित डेटाबेस कॉल को लपेटता है और अंततः जब डेटाबेस कॉल डेटा लौटाता है, तो यह आपके कोड को सूचित करता है।

function getCats() {
   return new Promise((resolve, reject) => {
       // make the database call
       db.cats((error, cats) => {
           // in case of an error, reject the promise by
           // calling "reject" function
           // Also pass the "error" object to the "reject" function
           // as an argument to get access to the error message 
           // in the code that calls this "getCats" function
           if (error) {
              reject(error);
              return;
           }
           
           // if there was no error, call "resolve" function
           // to resolve the promise. Promise will be resolved 
           // in case of successful database call
           // Also pass the data to "resolve" function
           // to access this data in the code that calls this
           // "getCats" function
           resolve(cats);
       });
   });
}

अब अपने रूट हैंडलर फ़ंक्शन में, db.cats(...) को कॉल करने के बजाय, इस getCats रैपर फ़ंक्शन को कॉल करें।

ऐसे दो तरीके हैं जिनसे आप एक वादा लौटाने वाले फ़ंक्शन को कॉल कर सकते हैं:

  • Promise-chaining (विवरण के लिए, ऊपर बताए गए लिंक पर जाएं)
  • async-await सिंटैक्स (अनुशंसित)

निम्नलिखित कोड उदाहरण async-await सिंटैक्स का उपयोग करता है। इसके लिए, पहले function कीवर्ड से पहले async कीवर्ड का उपयोग करके रूट हैंडलर फ़ंक्शन को async के रूप में चिह्नित करें। ऐसा करके हम इस रूट हैंडलर फंक्शन के अंदर await कीवर्ड का इस्तेमाल कर सकते हैं।

app.get('/pets', async function(req, res, next) {
    try {
       const cats = await getCats();
       // similar wrappers for other database calls
       const dogs = await getDogs();
       const budgies = await getBudgies();
       
       // render the pub template, passing in the data
       // fetched from the database 
       ...

     catch (error) {
       // catch block will be invoked if the promise returned by
       // the promise-based wrapper function is rejected
       // handle the error appropriately
     }
});

उपरोक्त कोड उदाहरण केवल यह दर्शाता है कि db.cats(...) डेटाबेस कॉल को एक वादे-आधारित आवरण में कैसे लपेटें और डेटाबेस से डेटा प्राप्त करने के लिए उस आवरण का उपयोग करें। इसी तरह, आप db.dogs(...) और db.budgies(...) कॉल के लिए रैपर बना सकते हैं।

प्रत्येक डेटाबेस कॉल के लिए एक अलग वादा-आधारित रैपर बनाने के बजाय, आदर्श रूप से, आपको एक पुन: उपयोग करने योग्य वादा-आधारित रैपर फ़ंक्शन बनाना चाहिए जो कॉल करने के लिए एक फ़ंक्शन लेता है और उस फ़ंक्शन कॉल को एक वादे में लपेटता है जैसा कि ऊपर दिए गए कोड उदाहरण में दिखाया गया है, यानी getCats function.

समानांतर डेटाबेस कॉल

मार्ग हैंडलर फ़ंक्शन में उपरोक्त कोड में ध्यान देने योग्य एक महत्वपूर्ण बात

const cats = await getCats();
const dogs = await getDogs();
const budgies = await getBudgies();

क्या यह अनुक्रमिक डेटाबेस कॉल की ओर ले जाएगा जो आप चाहते हैं या नहीं भी हो सकता है।

यदि ये डेटाबेस कॉल एक-दूसरे पर निर्भर नहीं हैं, तो आप Promise.all() विधि।

निम्नलिखित कोड उदाहरण दिखाता है कि आप Promise.all() का उपयोग करके समानांतर में अपने वादे-आधारित रैपर फ़ंक्शन को कैसे कॉल कर सकते हैं।

app.get('/pets', async function(req, res, next) {
    try {
       // "petsData" will be an array that will contain all the data from 
       // three database calls.
       const petsData = await Promise.all([getCats(), getDogs(), getBudgies()]);
       
       // render the pub template, passing in the data
       // fetched from the database 
       ...
 
     catch (error) {
       ...
     }
 });

मुझे आशा है कि यह आपके वर्तमान कोड में नेस्टेड डेटाबेस कॉल्स से छुटकारा पाने और अपने कोड में वादों का उपयोग शुरू करने में आपकी मदद करने के लिए पर्याप्त है।

10
Yousaf 21 अक्टूबर 2020, 18:32

यदि आप Nodejs के साथ MySQL का उपयोग करने का प्रयास कर रहे हैं, तो आपको जिस मॉड्यूल की तलाश करनी चाहिए वह mysql के बजाय mysql2 है।

mysql2 एक वादा आधारित दृष्टिकोण प्रदान करता है और नोडज के लिए mysql मॉड्यूल का एक बहुत परिष्कृत संस्करण है।

उदाहरण के लिए, किसी क्वेरी को निष्पादित करने के लिए,

  1. में mysql
con.query(sql_query, (err, rows, field)=>{ //some code here }
  1. mysql2 में, आप async दृष्टिकोण के साथ-साथ वादा दृष्टिकोण का उपयोग कर सकते हैं। साथ ही, mysql2 में तैयार किए गए कथन mysql की तुलना में अधिक आसान हैं।
//async approach
class A {
   static async fn(sql, params){
      const [data] = await con.execute(sql, [params]);
    return data;
    }
}

//promise approach remains same as **mysql** itself.

यहाँ के लिए प्रलेखन है mysql2 और अधिक दस्तावेज़

3
Srinath Kamath 4 पद 2020, 09:14

Promise.all() विधि आपके उपयोग के मामले की तरह समानांतर में एकाधिक कॉल करने के लिए एक अधिक प्रसिद्ध और क्लीनर तरीका प्रतीत होता है।

लेकिन एक और वैकल्पिक तरीका है। : एकाधिक कथन क्वेरी

इस सुविधा का उपयोग करने के लिए आपको इसे अपने कनेक्शन के लिए सक्षम करना होगा:

var connection = mysql.createConnection({multipleStatements: true});

एक बार सक्षम होने पर, आप किसी भी अन्य क्वेरी की तरह कई कथन क्वेरी निष्पादित कर सकते हैं:

db.query('SELECT cats; SELECT dogs', function (error, results, fields) {
  if (error) throw error;
  // `results` is an array with one element for every statement in the query:
  console.log(results[0]); // [{cat1,cat2}]
  console.log(results[1]); // [{dog1,dog2}]
});

यह तकनीकी रूप से अधिक कुशल है क्योंकि इसके लिए MySQL कनेक्शन के साथ कम आगे और पीछे की आवश्यकता होती है।

(हालांकि, यह सुविधा डिफ़ॉल्ट रूप से अक्षम है क्योंकि यह SQL इंजेक्शन हमलों के लिए अनुमति देता है यदि मान ठीक से बच नहीं गए हैं)। इस सुविधा का उपयोग करने के लिए आपको इसे अपने कनेक्शन के लिए सक्षम करना होगा।)

1
Ruchit Patel 7 पद 2020, 15:36

नोडज मानक लिब util.promisify का उपयोग करके बस mysql फ़ंक्शन को वादों में बदलें

उदाहरण:

const { promisify } = require('util');

const catsPromise = promisify(db.cats);
const dogsPromise = promisify(db.dogs);
const budgiesPromise = promisify(db.budgies);

async function routeHandler() {
  let err = null;

  try {
    const cats = await catsPromise();
    const dogs = await dogsPromise();
    const budgies = await budgiesPromise();
  } catch(error) {
    err = error;
  }

  if (err) {
    console.log(err);
    // you should res.end() or res.render(someErrorPage) here
    // failure to do so will leave the request open
  } else {
    res.render('bigScreen.pug', {
      'cats' : cats,
      'k9s': dogs,
      'budgies': budgies,
      'pretty' : true
    });
  }
}
1
louisbuchbinder 5 पद 2020, 17:25

यदि आपका डेटाबेस कॉलबैक का उपयोग करने के बजाय वादे लौटाता है, तो आप यह कर सकते हैं:

const cats = await db.cats();
const dogs = await db.dogs();
const budgies = await db.budgies();

res.render('bigScreen.pug', {
  cats : cats,
  k9s: dogs,
  budgies: budgies,
  pretty : true
});


// Or request them all in parallel instead of waiting for each to finish
const [
  cats,
  dogs,
  budgies
] = Promise.all([
  dg.cats(),
  dg.dogs(),
  db.budgies()
]);
1
Dylan Landry 21 अक्टूबर 2020, 16:40