क्या यह नए प्रोमिस () कंस्ट्रक्टर के अंदर एसिंक्स / वेट का उपयोग करने का एक एंटी-पैटर्न है?


103

मैं async.eachLimitएक समय में अधिकतम संचालन को नियंत्रित करने के लिए फ़ंक्शन का उपयोग कर रहा हूं ।

const { eachLimit } = require("async");

function myFunction() {
 return new Promise(async (resolve, reject) => {
   eachLimit((await getAsyncArray), 500, (item, callback) => {
     // do other things that use native promises.
   }, (error) => {
     if (error) return reject(error);
     // resolve here passing the next value.
   });
 });
}

जैसा कि आप देख सकते हैं, मैं myFunctionफ़ंक्शन को async घोषित नहीं कर सकता क्योंकि मेरे पास eachLimitफ़ंक्शन के दूसरे कॉलबैक के अंदर मान तक पहुंच नहीं है ।


"जैसा कि आप देख सकते हैं, मैं myFunction को async घोषित नहीं कर सकता" --- क्या आप अधिक विस्तृत कर सकते हैं?
झटके

1
ओह ठीक है क्षमा करें। मुझे कंस्ट्रक्टर की आवश्यकता है क्योंकि मुझे एक समय में 500 से अधिक अतुल्यकालिक संचालन से बचने के लिए async.eachLimit की आवश्यकता है। मैं टेक्स्ट फ़ाइलों से डेटा डाउनलोड कर रहा हूं और निकाल रहा हूं, मैं बहुत एसिंक्रोनस ऑपरेशंस से बचना चाहता हूं। डेटा निकालने के बाद, मुझे डेटा के साथ एक प्रॉमिस लौटाना चाहिए, और मैं इसे एसिंनएक्रिमेटिट के कॉलबैक से वापस करने में सक्षम नहीं होगा ।

1. आपको प्रतीक्षा की आवश्यकता क्यों है? Async पहले से ही एक नियंत्रण-प्रवाह तंत्र है। 2. यदि आप नोड के अंदर वादों के साथ async.js का उपयोग करना चाहते हैं। तो async-q पर एक नज़र डालें
slebetman

कॉलबैक नरक से बचने के लिए, और अगर कुछ फेंकता है, तो बाहरी वादा पकड़ लेगा।

जवाबों:


88

आप प्रभावी रूप से वादे के निर्माता निष्पादक कार्य के अंदर वादों का उपयोग कर रहे हैं, इसलिए यह वादा निर्माता विरोधी पैटर्न है

आपका कोड मुख्य जोखिम का एक अच्छा उदाहरण है: सभी त्रुटियों को सुरक्षित रूप से प्रचारित नहीं करना। क्यों पढ़ें वहाँ

इसके अलावा, async/ का उपयोग awaitएक ही जाल को और भी आश्चर्यजनक बना सकता है। की तुलना करें:

let p = new Promise(resolve => {
  ""(); // TypeError
  resolve();
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e)); // Catches it.

एक भोले (गलत) asyncसमकक्ष के साथ:

let p = new Promise(async resolve => {
  ""(); // TypeError
  resolve();
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e)); // Doesn't catch it!

पिछले एक के लिए अपने ब्राउज़र के वेब कंसोल में देखें।

पहला काम करता है क्योंकि प्रोमिस कंस्ट्रक्टर निष्पादक फ़ंक्शन में कोई भी तत्काल अपवाद नवनिर्मित वादे को आसानी से खारिज कर देता है (लेकिन किसी भी अंदर .thenआप अपने दम पर हैं)।

दूसरा काम नहीं करता है क्योंकि asyncफ़ंक्शन में कोई भी तत्काल अपवाद फ़ंक्शन द्वारा दिए गए निहित वादेasync को अस्वीकार कर देता है

चूंकि एक वादे के निर्माता निष्पादक फ़ंक्शन का वापसी मूल्य अप्रयुक्त है, यह बुरी खबर है!

तुम्हारा कोड

कोई कारण नहीं आप को परिभाषित नहीं कर सकते हैं myFunctionके रूप में async:

async function myFunction() {
  let array = await getAsyncArray();
  return new Promise((resolve, reject) => {
    eachLimit(array, 500, (item, callback) => {
      // do other things that use native promises.
    }, error => {
      if (error) return reject(error);
      // resolve here passing the next value.
    });
  });
}

यद्यपि आपके पास पुराना समसामयिक नियंत्रण पुस्तकालयों का उपयोग क्यों करें await?


12
आपको जरूरत नहीं है return await: return new Promiseपर्याप्त है।
लोन्सोमेडेय

2
मैं आधिकारिक तौर पर इस जवाब को स्वीकार करता हूं, मैंने ठीक वही कहा होगा :-)
बर्गी

1
@celoxxx यहाँ एक नज़र है । आप वास्तव में किए गए वादे के async.js का उपयोग कभी नहीं करना चाहिए
Bergi

1
@celoxxx बस प्रकार छोड़ता है और यह सादे js बन जाता है। आपको async.js का उपयोग नहीं करना चाहिए क्योंकि विभिन्न इंटरफेस - नोड-शैली कॉलबैक बनाम वादे - बहुत अधिक घर्षण का कारण बनता है और अनावश्यक जटिल और त्रुटि-प्रवण कोड का कारण बनता है।
बर्गी

1
मैं आपसे सहमत हूं ... लेकिन यह कोड पुराना है, और मैं घटनाओं + async.js (async की सीमा को नियंत्रित करने के लिए, फिर भी उपयोग करने के लिए मना कर रहा हूं। यदि आप एक बेहतर तरीका जानते हैं, तो कृपया कहें)।

21

मैं ऊपर दिए गए जवाबों से सहमत हूं और फिर भी, कभी-कभी यह आपके वादे के अंदर async करने के लिए शून्य है, खासकर यदि आप वादों को वापस करने वाले कई अभियानों को चेन करना चाहते हैं और then().then()नरक से बचते हैं। मैं उस स्थिति में कुछ इस तरह का उपयोग करने पर विचार करूंगा:

const operation1 = Promise.resolve(5)
const operation2 = Promise.resolve(15)
const publishResult = () => Promise.reject(`Can't publish`)

let p = new Promise((resolve, reject) => {
  (async () => {
    try {
      const op1 = await operation1;
      const op2 = await operation2;

      if (op2 == null) {
         throw new Error('Validation error');
      }

      const res = op1 + op2;
      const result = await publishResult(res);
      resolve(result)
    } catch (err) {
      reject(err)
    }
  })()
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e));
  1. Promiseकंस्ट्रक्टर को दिया गया फ़ंक्शन async नहीं है, इसलिए लिंटर त्रुटियां नहीं दिखाते हैं।
  2. सभी Async फ़ंक्शन का उपयोग करके अनुक्रमिक क्रम में कॉल किया जा सकता है await
  3. कस्टम त्रुटियों को Async संचालन के परिणामों को मान्य करने के लिए जोड़ा जा सकता है
  4. त्रुटि अंततः अच्छी तरह से पकड़ा जाता है।

एक कमी यह है कि आपको try/catchइसे लगाना और संलग्न करना याद रखना है reject


3
static getPosts(){
    return new Promise( (resolve, reject) =>{
        try {
            const res =  axios.get(url);
            const data = res.data;
            resolve(
                data.map(post => ({
                    ...post,
                    createdAt: new Date(post.createdAt)
                }))
            )
        } catch (err) {
            reject(err);                
        }
    })
}

निकालें और async इस समस्या को हल करेंगे। क्योंकि आपने प्रॉमिस ऑब्जेक्ट लागू किया है, वही पर्याप्त है।


1
तो आपके उदाहरण में, क्या axios.get(url)यह कार्य करेगा जैसा कि इसे कहा जाता है await axios.get(url)?
प्रेस्टनडॉक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.