Array.map के साथ async प्रतीक्षा का उपयोग करें


170

निम्नलिखित कोड दिया गया है:

var arr = [1,2,3,4,5];

var results: number[] = await arr.map(async (item): Promise<number> => {
        await callAsynchronousOperation(item);
        return item + 1;
    });

जो निम्नलिखित त्रुटि पैदा करता है:

TS2322: टाइप करें 'प्रॉमिस <नंबर> []' टाइप करने के लिए असाइन नहीं है 'नंबर []'। 'नंबर' टाइप करने के लिए 'वादा <नंबर> टाइप करने योग्य नहीं है।

मेरे द्वारा यह कैसे किया जा सकता है? मैं एक साथ कैसे बना async awaitऔर Array.mapकाम कर सकता हूं ?


6
आप एक सिंक्रोनस ऑपरेशन में एक तुल्यकालिक ऑपरेशन बनाने की कोशिश क्यों कर रहे हैं? arr.map()तुल्यकालिक है और एक वादा वापस नहीं करता है।
जुलाई

2
आप किसी फ़ंक्शन के लिए एक अतुल्यकालिक ऑपरेशन नहीं भेज सकते हैं, जैसे map, जो एक तुल्यकालिक की उम्मीद करता है, और यह काम करने की उम्मीद करता है।
हेरिटिक बंदर

1
@ jfriend00 मेरे पास आंतरिक कार्य में कई प्रतीक्षित कथन हैं। यह वास्तव में एक लंबा कार्य है और मैंने इसे पठनीय बनाने के लिए इसे सरल बनाया। मैंने अब एक प्रतीक्षित कॉल जोड़ा है ताकि यह स्पष्ट हो सके कि यह async क्यों होना चाहिए।
एलोन

आपको किसी ऐसी चीज़ का इंतजार करने की ज़रूरत है जो एक वादा लौटाती है, न कि कुछ जो एक सरणी देता है।
jfriend00

2
एक उपयोगी बात यह है कि हर बार जब आप किसी फ़ंक्शन को चिह्नित asyncकरते हैं, तो आप उस फ़ंक्शन को एक वादा वापस करते हैं। तो बेशक, async का एक नक्शा वादों की एक सरणी देता है :)
एंथनी मैनिंग-फ्रेंकलिन

जवाबों:


380

यहाँ समस्या यह है कि आप awaitवादे के बजाय वादों की एक सरणी के लिए कोशिश कर रहे हैं । यह वह नहीं करता है जो आप अपेक्षा करते हैं।

जब वस्तु को पारित awaitनहीं किया जाता है तो वह एक वादा नहीं है, awaitबस इसे हल करने की कोशिश करने के बजाय तुरंत मान लौटाता है। इसलिए जब से आपने awaitएक वादा के बजाय एक सरणी (प्रोमिस ऑब्जेक्ट्स) यहां पारित किया है , तो प्रतीक्षा द्वारा लौटाया गया मान केवल उस एरे का है, जो कि प्रकार का है Promise<number>[]

यहां आपको जो करने की आवश्यकता है उसे कॉल Promise.allकरने के mapक्रम में दिए गए सरणी पर कॉल करें ताकि इसे awaitआईएनजी से पहले एक ही प्रॉमिस में परिवर्तित किया जा सके ।

एमडीएन डॉक्स केPromise.all अनुसार :

Promise.all(iterable)विधि एक वादा रिटर्न का समाधान करता है जब iterable बहस में वादे के सभी समाधान कर लिया है, या पहले से पारित कर दिया वादा है कि अस्वीकार की कारण के साथ अस्वीकार करता है।

तो आपके मामले में:

var arr = [1, 2, 3, 4, 5];

var results: number[] = await Promise.all(arr.map(async (item): Promise<number> => {
    await callAsynchronousOperation(item);
    return item + 1;
}));

यह आपके द्वारा सामना की जा रही विशिष्ट त्रुटि को हल करेगा।


1
:कॉलन का क्या मतलब है?
डैनियल का कहना है कि

11
@DanielPendergast यह टाइपस्क्रिप्ट में टाइप एनोटेशन के लिए है।
अजादि32

Async मानचित्र फ़ंक्शन के अंदर callAsynchronousOperation(item);और उसके बिना कॉल करने में क्या अंतर है await?
nerdizzle

@nerdizzle यह एक और प्रश्न के लिए एक अच्छे उम्मीदवार की तरह लगता है। मूल रूप से, हालांकि, awaitफ़ंक्शन के साथ अतुल्यकालिक ऑपरेशन के पूरा होने से पहले (या विफल) होने का इंतजार करेंगे, अन्यथा यह तुरंत प्रतीक्षा के बाद भी जारी रहेगा।
Ajedi32

@ प्रतिक्रिया के लिए Ajedi32 thx। लेकिन async मानचित्र में प्रतीक्षा के बिना फ़ंक्शन के पुनः परिणाम की प्रतीक्षा करना संभव नहीं है?
nerdizzle

15

यदि आप देशी वादों का उपयोग नहीं कर रहे हैं लेकिन ब्लूबर्ड का उपयोग कर रहे हैं तो इसके लिए एक और उपाय है।

आप array.map और Promise.all को मिलाकर Promise.map () का उपयोग करने का भी प्रयास कर सकते हैं

आप मामले में:

  var arr = [1,2,3,4,5];

  var results: number[] = await Promise.map(arr, async (item): Promise<number> => {
    await callAsynchronousOperation(item);
    return item + 1;
  });

2
यह अलग है - यह समानांतर में सभी संचालन नहीं करता है, बल्कि उन्हें अनुक्रम में निष्पादित करता है।
एंड्री टर्सकस

5
@AndreyTserkus Promise.mapSeriesया Promise.eachअनुक्रमिक हैं, Promise.mapउन सभी को एक साथ शुरू करता है।
कीच्लस

1
@AndreyTserkus आप concurrencyविकल्प प्रदान करके समानांतर में सभी या कुछ ऑपरेशन चला सकते हैं ।

11
यह उल्लेखनीय है कि यह एक वैनिला जेएस नहीं है।
मीकल

@ मिचल यस, यह सिंटेक्सएयर है
सीएस


2

मैं Promise.all का उपयोग करने की सलाह देता हूं, जैसा कि ऊपर उल्लेख किया गया है, लेकिन अगर आपको वास्तव में ऐसा लगता है कि आप उस दृष्टिकोण से बचना चाहते हैं, तो आप एक या किसी अन्य लूप के लिए कर सकते हैं:

const arr = [1,2,3,4,5];
let resultingArr = [];
for (let i in arr){
  await callAsynchronousOperation(i);
  resultingArr.push(i + 1)
}

6
Promise.all सरणी के प्रत्येक तत्व के लिए async होगा। यह एक सिंक होगा, इसे अगले एक को शुरू करने के लिए एक तत्व को खत्म करने के लिए इंतजार करना होगा।
सैंटियागो मेंडोज़ा रामिरेज़

इस दृष्टिकोण की कोशिश करने वालों के लिए, ध्यान दें कि .. के लिए एक सरणी सामग्री को पुनरावृत्त करने का उचित तरीका है, जबकि for..in सूचकांकों पर आधारित है।
राल्फाइड

2

एक सरणी के सभी तत्वों को अतुल्यकालिक रूप से संसाधित करने और ऑर्डर को संरक्षित करने के लिए नीचे दिया गया समाधान:

const arr = [1, 2, 3, 4, 5, 6, 7, 8];
const randomDelay = () => new Promise(resolve => setTimeout(resolve, Math.random() * 1000));

const calc = async n => {
  await randomDelay();
  return n * 2;
};

const asyncFunc = async () => {
  const unresolvedPromises = arr.map(n => calc(n));
  const results = await Promise.all(unresolvedPromises);
};

asyncFunc();

साथ ही कोडपेन भी ।

ध्यान दें कि हम केवल Promise.all के लिए "प्रतीक्षा" कर रहे हैं। हम कई बार "इंतजार" के बिना कैल्क कहते हैं, और हम तुरंत अनसुलझे वादों की एक सरणी एकत्र करते हैं। तब Promise.all उन सभी के समाधान की प्रतीक्षा करता है और क्रम में हल किए गए मानों के साथ एक सरणी देता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.