प्रतीक्षा करें जब तक कि सभी वादे पूरे न हों, भले ही कुछ खारिज कर दिया जाए


405

मान लीजिए कि मेरे पास एक सेट है Promiseजो नेटवर्क अनुरोध कर रहा है, जिनमें से एक विफल हो जाएगा:

// http://does-not-exist will throw a TypeError
var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]

Promise.all(arr)
  .then(res => console.log('success', res))
  .catch(err => console.log('error', err)) // This is executed   

मान लीजिए कि मैं इन सभी को समाप्त होने तक इंतजार करना चाहता हूं, चाहे कोई भी असफल हो। एक संसाधन के लिए एक नेटवर्क त्रुटि हो सकती है जिसे मैं बिना जी सकता हूं, लेकिन जो मुझे मिल सकता है, मैं आगे बढ़ने से पहले चाहता हूं। मैं नेटवर्क विफलताओं को इनायत से संभालना चाहता हूं।

चूँकि Promises.allइसके लिए कोई जगह नहीं बची है, एक वादे के पुस्तकालय का उपयोग किए बिना, इसे संभालने के लिए अनुशंसित पैटर्न क्या है?


अस्वीकार किए गए वादों के लिए परिणामी सरणी में क्या लौटाया जाना चाहिए?
कुबा व्यारोसेक

9
ES6 वादे ऐसी किसी भी पद्धति का समर्थन नहीं करते हैं (और वर्तमान में ब्लूबर्ड की तुलना में धीमा है )। इसके अलावा, सभी ब्राउज़र या इंजन अभी तक उनका समर्थन नहीं करते हैं। मैं दृढ़ता से ब्लूबर्ड का उपयोग करने की सिफारिश करूंगा , जो allSettledकि आपके रोल को पूरा किए बिना आपकी आवश्यकता को पूरा करता है।
दान पेंट्री

@ KubaWyrostek मुझे लगता है कि आप कारण को सामने लाते हैं Promise.all में यह व्यवहार नहीं है, जो मुझे लगता है कि समझ में आता है। यह ऐसा नहीं है कि यह कैसे काम करता है, लेकिन एक वैकल्पिक दृष्टिकोण यह कहना होगा कि Promise.all को एक विशेष वादा वापस करना चाहिए जो कभी भी विफल नहीं होता है - और आपको वह त्रुटि मिलेगी जिसे विफल वादे का प्रतिनिधित्व करने वाले तर्क के रूप में फेंक दिया गया था।
नाथन हेगन

डैन ने जो साझा किया है, उसे जोड़ने के लिए, एल्डसेटल्ड / सेटलएबिलिटी जैसी कार्यक्षमता जिसे ब्लूबर्ड द्वारा "प्रतिबिंबित" फ़ंक्शन के माध्यम से उपयोग किया जा सकता है।
user3344977

2
@ कोली: हम्म, मुझे ऐसा नहीं लगता। Promise.allजैसे ही कोई भी वादे को अस्वीकार करता है, वैसे ही अस्वीकार कर देगा, इसलिए आपका प्रस्तावित मुहावरा यह गारंटी नहीं देता है कि सभी वादे निपट चुके हैं।
जोर्ग डब्ल्यू मित्तग

जवाबों:


309

अद्यतन, आप शायद अंतर्निहित मूल का उपयोग करना चाहते हैं Promise.allSettled:

Promise.allSettled([promise]).then(([result]) => {
   //reach here regardless
   // {status: "fulfilled", value: 33}
});

एक मज़ेदार तथ्य के रूप में, नीचे दिया गया यह उत्तर भाषा में उस पद्धति को जोड़ने की पूर्व कला थी:]


यकीन है, तुम सिर्फ एक की जरूरत है reflect:

const reflect = p => p.then(v => ({v, status: "fulfilled" }),
                            e => ({e, status: "rejected" }));

reflect(promise).then((v => {
    console.log(v.status);
});

या ES5 के साथ:

function reflect(promise){
    return promise.then(function(v){ return {v:v, status: "fulfilled" }},
                        function(e){ return {e:e, status: "rejected" }});
}


reflect(promise).then(function(v){
    console.log(v.status);
});

या आपके उदाहरण में:

var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]

Promise.all(arr.map(reflect)).then(function(results){
    var success = results.filter(x => x.status === "fulfilled");
});

3
मुझे लगता है कि यह एक महान समाधान है। क्या आप एक सरल वाक्यविन्यास को शामिल करने के लिए इसमें संशोधन कर सकते हैं? इस मुद्दे की जड़ यह है कि यदि आप उप-वादों में त्रुटियों को संभालना चाहते हैं, तो आपको उन्हें पकड़ना चाहिए और त्रुटि को वापस करना चाहिए। उदाहरण के लिए: gist.github.com/nhagen/a1d36b39977822c224b8
नाथन हेगन

3
@ नथनहेजेन आपको यह पता लगाने देता है कि क्या अस्वीकार किया और क्या पूरा किया और समस्या को एक पुन: प्रयोज्य ऑपरेटर तक पहुंचाता है।
बेंजामिन ग्रुएनबाम

4
अपने स्वयं के मुद्दे के जवाब में मैंने निम्नलिखित npm पैकेज बनाया है: github.com/Bucabug/promise-reflect npmjs.com/package/promise-reflect
SamF

2
मैं कुछ समय पहले इस मुद्दे पर आया था और मैंने इसके लिए यह npm
velocity_distance

5
शब्द है reflectकंप्यूटर विज्ञान में एक आम शब्द? क्या आप इसे विकिपीडिया या किसी चीज़ की तरह समझा सकते हैं मैं इसके लिए कड़ी मेहनत कर रहा था, Promise.all not even first rejectलेकिन "रिफ्लेक्ट" खोजना नहीं जानता था। क्या ES6 में Promise.reflect"प्रोमिस.ल्ल लेकिन वास्तव में सभी" जैसा है?
Noitidart

253

इसी तरह के जवाब, लेकिन शायद ES6 के लिए अधिक मुहावरेदार:

const a = Promise.resolve(1);
const b = Promise.reject(new Error(2));
const c = Promise.resolve(3);

Promise.all([a, b, c].map(p => p.catch(e => e)))
  .then(results => console.log(results)) // 1,Error: 2,3
  .catch(e => console.log(e));


const console = { log: msg => div.innerHTML += msg + "<br>"};
<div id="div"></div>

लौटाए गए मानों के प्रकार (ओं) के आधार पर, त्रुटियों को अक्सर आसानी से पर्याप्त रूप से भिन्न किया जा सकता है (उदाहरण के undefinedलिए "परवाह न करें", typeofसादे गैर-वस्तु मानों के लिए result.message, result.toString().startsWith("Error:")आदि)


1
@KarlBateman मुझे लगता है कि आप भ्रमित हैं। आदेश फ़ंक्शंस हल करते हैं या अस्वीकार नहीं करते हैं क्योंकि यह .map(p => p.catch(e => e))हिस्सा सभी अस्वीकार किए गए मानों को हल करता है, इसलिए Promise.allअभी भी सब कुछ खत्म होने की प्रतीक्षा करता है, चाहे वे व्यक्तिगत फ़ंक्शन हल करें या अस्वीकार करें, भले ही वे कितने समय तक लें। कोशिश करो।
जिब

39
.catch(e => console.log(e));यह कभी नहीं कहा जाता है क्योंकि यह कभी नहीं विफल होता है
बजे

4
@ bfred.it यह सही है। हालांकि समाप्ति के साथ वादा श्रृंखला catchआम तौर पर अच्छा अभ्यास IMHO है
जिब

2
@ सुहेलगुप्ता यह त्रुटि पकड़ता है eऔर इसे नियमित (सफलता) मान के रूप में लौटाता है। p.catch(function(e) { return e; })केवल कम के रूप में ही। returnनिहित है।
जिब

1
@JustinReusnow पहले से ही टिप्पणियों में शामिल है। यदि आप बाद में कोड जोड़ते हैं तो चेन को समाप्त करने के लिए हमेशा अच्छा अभ्यास करें।
जिब

71

बेंजामिन का जवाब इस मुद्दे को हल करने के लिए एक महान अमूर्तता प्रदान करता है, लेकिन मैं कम सार समाधान की उम्मीद कर रहा था। इस मुद्दे को हल करने का स्पष्ट तरीका केवल .catchआंतरिक वादों पर कॉल करना है, और उनके कॉलबैक से त्रुटि वापस करना है।

let a = new Promise((res, rej) => res('Resolved!')),
    b = new Promise((res, rej) => rej('Rejected!')),
    c = a.catch(e => { console.log('"a" failed.'); return e; }),
    d = b.catch(e => { console.log('"b" failed.'); return e; });

Promise.all([c, d])
  .then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
  .catch(err => console.log('Catch', err));

Promise.all([a.catch(e => e), b.catch(e => e)])
  .then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
  .catch(err => console.log('Catch', err));

इसे एक कदम आगे बढ़ाते हुए, आप एक सामान्य कैच हैंडलर लिख सकते हैं जो इस तरह दिखता है:

const catchHandler = error => ({ payload: error, resolved: false });

तो आप कर सकते हैं

> Promise.all([a, b].map(promise => promise.catch(catchHandler))
    .then(results => console.log(results))
    .catch(() => console.log('Promise.all failed'))
< [ 'Resolved!',  { payload: Promise, resolved: false } ]

इसके साथ समस्या यह है कि पकड़े गए मूल्यों में गैर-पकड़े गए मूल्यों की तुलना में एक अलग इंटरफ़ेस होगा, इसलिए इसे साफ करने के लिए आप कुछ कर सकते हैं:

const successHandler = result => ({ payload: result, resolved: true });

तो अब आप यह कर सकते हैं:

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
    .then(results => console.log(results.filter(result => result.resolved))
    .catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]

फिर इसे DRY में रखने के लिए, आपको बेंजामिन का जवाब मिलेगा:

const reflect = promise => promise
  .then(successHandler)
  .catch(catchHander)

अब यह कैसा दिखता है

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
    .then(results => console.log(results.filter(result => result.resolved))
    .catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]

दूसरे समाधान के लाभ यह हैं कि इसका सार और DRY। नकारात्मक पक्ष यह है कि आपके पास अधिक कोड है, और आपको चीजों को लगातार बनाने के लिए अपने सभी वादों को प्रतिबिंबित करना याद रखना होगा।

मैं स्पष्ट और KISS, लेकिन वास्तव में कम मजबूत के रूप में मेरे समाधान की विशेषताएँ हैं। इंटरफ़ेस गारंटी नहीं देता है कि आप वास्तव में जानते हैं कि वादा सफल हुआ या विफल।

उदाहरण के लिए आपके पास यह हो सकता है:

const a = Promise.resolve(new Error('Not beaking, just bad'));
const b = Promise.reject(new Error('This actually didnt work'));

यह द्वारा पकड़ा नहीं जाएगा a.catch, तो

> Promise.all([a, b].map(promise => promise.catch(e => e))
    .then(results => console.log(results))
< [ Error, Error ]

यह बताने का कोई तरीका नहीं है कि कौन सा घातक था और कौन सा नहीं था। यदि यह महत्वपूर्ण है तो आप इसे लागू करना चाहते हैं और इंटरफ़ेस को ट्रैक करते हैं कि यह सफल था या नहीं (जो किreflect करता है)।

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

> Promise.all([a.catch(() => undefined), b.catch(() => undefined)])
    .then((results) => console.log('Known values: ', results.filter(x => typeof x !== 'undefined')))
< [ 'Resolved!' ]

मेरे मामले में, मुझे त्रुटि जानने की आवश्यकता नहीं है या यह कैसे विफल हुआ - मुझे सिर्फ यह ध्यान है कि मेरे पास मूल्य है या नहीं। मैं विशिष्ट त्रुटि लॉग करने के बारे में वादा चिंता उत्पन्न करता है कि समारोह में दूँगा।

const apiMethod = () => fetch()
  .catch(error => {
    console.log(error.message);
    throw error;
  });

इस तरह, शेष एप्लिकेशन इसकी त्रुटि को अनदेखा कर सकता है यदि वह चाहे, और इसे अपरिभाषित मान के रूप में मान सकता है।

मैं अपने उच्च स्तर के कार्यों क्यों अपनी निर्भरता में विफल रहा है पर विवरण के बारे में सुरक्षित रूप से और न चिंता विफल चाहते हैं, और मुझे लगता है कि दुविधा यह करना है जब मैं भी सूखने के लिए KISS पसंद करते हैं - जो अंततः यही कारण है कि मैं का उपयोग नहीं करने का विकल्प चुना reflect


1
@ बैंजामिन मुझे लगता है कि @ नाथन का समाधान बहुत ही सीधा और मुहावरेदार है Promise। आपके reflectसुधार कोड का पुन: उपयोग करते समय, यह अमूर्तता का एक और स्तर भी स्थापित करता है। चूँकि नाथन के जवाब से अब तक केवल आपकी तुलना में कुछ अंश ही मिले हैं, मुझे आश्चर्य है कि क्या यह उसके समाधान के साथ किसी मुद्दे का संकेत है, जिसे मैंने अभी तक मान्यता नहीं दी है।

2
@ LUH3417 यह समाधान वैचारिक रूप से कम ध्वनि है क्योंकि यह त्रुटियों को मूल्यों के रूप में मानता है और त्रुटियों को गैर-त्रुटियों से अलग नहीं करता है। उदाहरण के लिए यदि वादों में से एक वैध रूप से एक मूल्य के लिए हल होता है जिसे फेंका जा सकता है (जो पूरी तरह से संभव है) तो यह बहुत बुरी तरह से टूट जाता है।
बेंजामिन ग्रुएनबाम

2
@BenjaminGruenbaum तो उदाहरण के लिए, new Promise((res, rej) => res(new Error('Legitimate error'))से अलग नहीं होगा new Promise(((res, rej) => rej(new Error('Illegitimate error'))? या आगे, आप फ़िल्टर नहीं कर पाएंगे x.status? मैं इस बिंदु को अपने उत्तर में जोड़ूंगा ताकि अंतर अधिक स्पष्ट हो
नाथन हेगन

3
इसका कारण यह है कि यह एक खराब विचार है क्योंकि यह केवल एक विशिष्ट Promise.all()संस्करण में उपयोग किए जा रहे किसी विशिष्ट उपयोग के मामले में वादे को लागू करता है, यह भी वादा उपभोक्ता को समझ में आता है कि एक विशिष्ट वादा अस्वीकार नहीं होगा लेकिन होगा यह त्रुटि है। वास्तव में इस reflect()पद्धति को कम 'सार' कहा जा सकता है और इसे स्पष्ट करके अधिक स्पष्ट किया जा सकता है PromiseEvery(promises).then(...)। बेंजामिन की तुलना में ऊपर दिए गए उत्तर की जटिलता को इस समाधान के बारे में बहुत कुछ कहना चाहिए।
नील

33

वहां एक है एक समारोह के लिए समाप्त प्रस्ताव है जो इस Promise.allSettledदेशी को पूरा कर सकता है, वेनिला जावास्क्रिप्ट में: जिसने इसे चरण 4 में बनाया है, इसे ES2020 में आधिकारिक किया गया है, और इसे सभी आधुनिक वातावरणों में लागू किया गया है । यह इस अन्य उत्तरreflect में फ़ंक्शन के समान है । यहाँ एक उदाहरण है, प्रस्ताव पृष्ठ से। इससे पहले, आपको करना होगा:

function reflect(promise) {
  return promise.then(
    (v) => {
      return { status: 'fulfilled', value: v };
    },
    (error) => {
      return { status: 'rejected', reason: error };
    }
  );
}

const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.all(promises.map(reflect));
const successfulPromises = results.filter(p => p.status === 'fulfilled');

Promise.allSettledइसके बजाय का उपयोग करना , ऊपर के बराबर होगा:

const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.allSettled(promises);
const successfulPromises = results.filter(p => p.status === 'fulfilled');

आधुनिक वातावरण का उपयोग करने वाले बिना किसी पुस्तकालय के इस विधि का उपयोग कर सकेंगे । उन में, निम्नलिखित स्निपेट समस्याओं के बिना चलना चाहिए:

Promise.allSettled([
  Promise.resolve('a'),
  Promise.reject('b')
])
  .then(console.log);

आउटपुट:

[
  {
    "status": "fulfilled",
    "value": "a"
  },
  {
    "status": "rejected",
    "reason": "b"
  }
]

पुराने ब्राउज़रों के लिए, यहां एक कल्पना-युक्त पॉलीफ़िल है


1
यह स्टेज 4 है और इसे ES2020 में उतारा जाना चाहिए।
एस्टुस फ्लास्क

नोड 12 में भी उपलब्ध है:
कैलम एम

यहां तक ​​कि अगर अन्य उत्तर अभी भी मान्य हैं, तो यह अधिक बढ़ जाना चाहिए क्योंकि यह इस मुद्दे को हल करने का सबसे वर्तमान तरीका है।
जैकब

9

मैं वास्तव में बेंजामिन के उत्तर को पसंद करता हूं, और वह मूल रूप से सभी वादों को हमेशा हल करने वाले-लेकिन-कभी-कभी-त्रुटि-जैसे-ए-परिणाम वाले लोगों में बदल देता है। :)
यहाँ आपके अनुरोध पर मेरा प्रयास है कि आप विकल्पों की तलाश कर रहे हैं। यह विधि केवल त्रुटियों को वैध परिणाम के रूप में मानती है, और Promise.allअन्यथा के समान कोडित है :

Promise.settle = function(promises) {
  var results = [];
  var done = promises.length;

  return new Promise(function(resolve) {
    function tryResolve(i, v) {
      results[i] = v;
      done = done - 1;
      if (done == 0)
        resolve(results);
    }

    for (var i=0; i<promises.length; i++)
      promises[i].then(tryResolve.bind(null, i), tryResolve.bind(null, i));
    if (done == 0)
      resolve(results);
  });
}

इसे आमतौर पर कहा जाता है settle। हमारे पास वह भी ब्लूबर्ड में है, मुझे बेहतर परिलक्षित होता है लेकिन जब आप किसी ऐरे के लिए होते हैं तो यह एक व्यवहार्य समाधान होता है।
बेंजामिन ग्रुएनबाम

2
ठीक है, समझौता वास्तव में एक बेहतर नाम होगा। :)
कुबा व्यारोसेक

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

क्या आप Promiseकंस्ट्रक्टर का सही इस्तेमाल कर सकते हैं (और उस var resolveचीज़ से बचें )?
बरगी

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

5
var err;
Promise.all([
    promiseOne().catch(function(error) { err = error;}),
    promiseTwo().catch(function(error) { err = error;})
]).then(function() {
    if (err) {
        throw err;
    }
});

Promise.allकिसी भी अस्वीकार कर दिया वादा निगल और, एक चर में त्रुटि की दुकान जब वादे के सभी समाधान कर लिया है तो यह वापस आ जाएगी होगा। फिर आप त्रुटि को फिर से फेंक सकते हैं, या जो कुछ भी कर सकते हैं। इस तरह, मुझे लगता है कि आप पहले वाले के बजाय अंतिम अस्वीकृति प्राप्त करेंगे।


1
ऐसा लगता है कि यह एक सरणी बनाकर और उपयोग करके एग्रीगेट को पूरा कर सकता है err.push(error), इसलिए सभी त्रुटियों को बुदबुदाया जा सकता है।
ps2goat

4

मेरे पास एक ही समस्या थी और इसे निम्नलिखित तरीके से हल किया है:

const fetch = (url) => {
  return node-fetch(url)
    .then(result => result.json())
    .catch((e) => {
      return new Promise((resolve) => setTimeout(() => resolve(fetch(url)), timeout));
    });
};

tasks = [fetch(url1), fetch(url2) ....];

Promise.all(tasks).then(......)

उस मामले में Promise.allहर वादा के लिए इंतजार करना होगा resolvedया rejectedराज्य में आ जाएगा ।

और इस समाधान को होने से हम catchगैर-अवरुद्ध तरीके से "निष्पादन को रोक रहे हैं" । वास्तव में, हम कुछ भी नहीं रोक रहे हैं, हम बस Promiseएक लंबित स्थिति में वापस लौट रहे हैं जो Promiseसमय समाप्त होने के बाद हल होने पर एक और वापस आ जाता है ।


लेकिन जब आप दौड़ेंगे तो सभी वादों को पूरा करेंगे Promise.all। मैं एक तरीका खोज रहा हूँ जब सभी वादों का आह्वान किया जाए, लेकिन उन्हें स्वयं नहीं किया जाए। धन्यवाद।
सूडोप्ल्ज़

@SudoPlz विधि all()ऐसा करती है, यह सभी वादों के पूरा होने या कम से कम एक अस्वीकृति की प्रतीक्षा करती है।
user1016265

यह सच है, लेकिन यह सिर्फ इंतजार नहीं करता है, यह वास्तव में इस प्रक्रिया को शुरू / आग लगाता है। यदि आप कुछ और वादों को पूरा करना चाहते हैं जो संभव नहीं होगा, तो बेज़ार .allसब कुछ खत्म हो जाएगा ।
सूदप्लज

@SudoPlz को उम्मीद है कि इससे आपकी राय बदल जाएगी jsfiddle.net/d1z1vey5
user1016265

3
मुझे सही साबित होना है। अब तक मैंने सोचा था कि वादे केवल तभी चलते हैं जब कोई उन्हें बुलाता है (उर्फ thenया एक .allकॉल) लेकिन वे तब पैदा होते हैं जब वे पैदा होते हैं।
सूडोप्लज

2

यह क्यू के साथ संगत होना चाहिए :

if(!Promise.allSettled) {
    Promise.allSettled = function (promises) {
        return Promise.all(promises.map(p => Promise.resolve(p).then(v => ({
            state: 'fulfilled',
            value: v,
        }), r => ({
            state: 'rejected',
            reason: r,
        }))));
    };
}

2

बेंजामिन Gruenbaum उत्तर निश्चित रूप से महान है,। लेकिन मैं यह भी देख सकता हूं कि अमथन के स्तर के साथ नाथन हेगन का दृष्टिकोण अस्पष्ट था। छोटी वस्तु जैसे गुण होनाe & v या तो मदद नहीं करते हैं, लेकिन निश्चित रूप से इसे बदला जा सकता है।

जावास्क्रिप्ट में मानक त्रुटि ऑब्जेक्ट है, जिसे कहा जाता है Error,। आदर्श रूप से आप हमेशा इसके उदाहरण / वंशज को फेंकते हैं। लाभ यह है कि आप कर सकते हैं instanceof Error, और आप जानते हैं कि कुछ त्रुटि है।

इसलिए इस विचार का उपयोग करते हुए, यहाँ समस्या पर मेरा विचार है।

मूल रूप से त्रुटि को पकड़ें, यदि त्रुटि टाइप एरर की नहीं है, तो एरर ऑब्जेक्ट के अंदर एरर को रैप करें। परिणामी सरणी में या तो हल किए गए मान होंगे, या आप जिन ऑब्जेक्ट्स को चेक कर सकते हैं उन्हें एरर कर सकते हैं।

कैच के अंदर का उदाहरण, यदि आप reject("error")इसके बजाय कुछ बाहरी लाइब्रेरी का उपयोग करते हैं , तो हो सकता हैreject(new Error("error"))

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

इसे करने का एक और फायदा, सरणी को नष्ट करना सरल रखा गया है।

const [value1, value2] = PromiseAllCatch(promises);
if (!(value1 instanceof Error)) console.log(value1);

के बजाय

const [{v: value1, e: error1}, {v: value2, e: error2}] = Promise.all(reflect..
if (!error1) { console.log(value1); }

आप यह तर्क दे सकते हैं कि !error1चेक एक इंस्टॉफ़ की तुलना में सरल है, लेकिन आपका भी दोनों को नष्ट करना है v & e

function PromiseAllCatch(promises) {
  return Promise.all(promises.map(async m => {
    try {
      return await m;
    } catch(e) {
      if (e instanceof Error) return e;
      return new Error(e);
    }
  }));
}


async function test() {
  const ret = await PromiseAllCatch([
    (async () => "this is fine")(),
    (async () => {throw new Error("oops")})(),
    (async () => "this is ok")(),
    (async () => {throw "Still an error";})(),
    (async () => new Error("resolved Error"))(),
  ]);
  console.log(ret);
  console.log(ret.map(r =>
    r instanceof Error ? "error" : "ok"
    ).join(" : ")); 
}

test();


2

अस्वीकार करने के बजाय, इसे किसी वस्तु से हल करें। जब आप वादे पर अमल कर रहे हैं तो आप ऐसा कुछ कर सकते हैं

const promise = arg => {
  return new Promise((resolve, reject) => {
      setTimeout(() => {
        try{
          if(arg != 2)
            return resolve({success: true, data: arg});
          else
            throw new Error(arg)
        }catch(e){
          return resolve({success: false, error: e, data: arg})
        }
      }, 1000);
  })
}

Promise.all([1,2,3,4,5].map(e => promise(e))).then(d => console.log(d))


1
यह एक अच्छा काम दिखता है, सुरुचिपूर्ण नहीं है, लेकिन काम करेगा
सनी ताम्बी

1

मैं निम्नलिखित ऑफर एक अलग दृष्टिकोण लगता है ... तुलना fn_fast_fail()के साथ fn_slow_fail()... हालांकि इसमें इस तरह के रूप में विफल नहीं हुआ ... आप एक या दोनों अगर जाँच कर सकते हैं aऔर bका एक उदाहरण है Errorऔर throwहै कि Errorआप तक पहुंचने में यह चाहते हैं catchब्लॉक (जैसे if (b instanceof Error) { throw b; })। Jsfiddle देखें ।

var p1 = new Promise((resolve, reject) => { 
    setTimeout(() => resolve('p1_delayed_resolvement'), 2000); 
}); 

var p2 = new Promise((resolve, reject) => {
    reject(new Error('p2_immediate_rejection'));
});

var fn_fast_fail = async function () {
    try {
        var [a, b] = await Promise.all([p1, p2]);
        console.log(a); // "p1_delayed_resolvement"
        console.log(b); // "Error: p2_immediate_rejection"
    } catch (err) {
        console.log('ERROR:', err);
    }
}

var fn_slow_fail = async function () {
    try {
        var [a, b] = await Promise.all([
            p1.catch(error => { return error }),
            p2.catch(error => { return error })
        ]);
        console.log(a); // "p1_delayed_resolvement"
        console.log(b); // "Error: p2_immediate_rejection"
    } catch (err) {
        // we don't reach here unless you throw the error from the `try` block
        console.log('ERROR:', err);
    }
}

fn_fast_fail(); // fails immediately
fn_slow_fail(); // waits for delayed promise to resolve

0

यहाँ मेरा रिवाज है settledPromiseAll()

const settledPromiseAll = function(promisesArray) {
  var savedError;

  const saveFirstError = function(error) {
    if (!savedError) savedError = error;
  };
  const handleErrors = function(value) {
    return Promise.resolve(value).catch(saveFirstError);
  };
  const allSettled = Promise.all(promisesArray.map(handleErrors));

  return allSettled.then(function(resolvedPromises) {
    if (savedError) throw savedError;
    return resolvedPromises;
  });
};

की तुलना में Promise.all

  • यदि सभी वादों को हल किया जाता है, तो यह बिल्कुल मानक के रूप में प्रदर्शन करता है।

  • यदि अधिक वादों में से एक को अस्वीकार कर दिया जाता है, तो यह पहले वाले को मानक एक के रूप में बहुत ही अस्वीकार कर देता है लेकिन इसके विपरीत यह सभी वादों को हल करने / अस्वीकार करने की प्रतीक्षा करता है।

बहादुर के लिए हम बदल सकते हैं Promise.all():

(function() {
  var stdAll = Promise.all;

  Promise.all = function(values, wait) {
    if(!wait)
      return stdAll.call(Promise, values);

    return settledPromiseAll(values);
  }
})();

कारफूल । सामान्य तौर पर हम कभी भी बिल्ट-इन नहीं बदलते हैं, क्योंकि यह अन्य असंबंधित जेएस लाइब्रेरी को तोड़ सकता है या जेएस मानकों के भविष्य में बदलाव के साथ टकरा सकता है।

मेरा settledPromiseallपिछड़ा संगत हैPromise.all और इसकी कार्यक्षमता बढ़ाता है।

जो लोग मानक विकसित कर रहे हैं - वे इसे नए प्रॉमिस मानक में शामिल क्यों नहीं करते?


0

Promise.allआधुनिक async/awaitदृष्टिकोण का उपयोग करने के साथ

const promise1 = //...
const promise2 = //...

const data = await Promise.all([promise1, promise2])

const dataFromPromise1 = data[0]
const dataFromPromise2 = data[1]

-1

मुझे क्या करना होगा:

var err = [fetch('index.html').then((success) => { return Promise.resolve(success); }).catch((e) => { return Promise.resolve(e); }),
fetch('http://does-not-exist').then((success) => { return Promise.resolve(success); }).catch((e) => { return Promise.resolve(e); })];

Promise.all(err)
.then(function (res) { console.log('success', res) })
.catch(function (err) { console.log('error', err) }) //never executed

-1

आप तुल्यकालिक निष्पादक nsynjs के माध्यम से अपने तर्क को क्रमिक रूप से निष्पादित कर सकते हैं । यह प्रत्येक वादे पर विराम लगाएगा, रिज़ॉल्यूशन / अस्वीकृति की प्रतीक्षा करेगा, और या तो dataसंपत्ति के लिए रिज़ॉल्यूशन के परिणाम को असाइन करेगा , या एक अपवाद फेंक देगा (हैंडलिंग के लिए जिसे आपको कोशिश / पकड़ने के ब्लॉक की आवश्यकता होगी)। यहाँ एक उदाहरण है:

function synchronousCode() {
    function myFetch(url) {
        try {
            return window.fetch(url).data;
        }
        catch (e) {
            return {status: 'failed:'+e};
        };
    };
    var arr=[
        myFetch("https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"),
        myFetch("https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/NONEXISTANT.js"),
        myFetch("https://ajax.NONEXISTANT123.com/ajax/libs/jquery/2.0.0/NONEXISTANT.js")
    ];
    
    console.log('array is ready:',arr[0].status,arr[1].status,arr[2].status);
};

nsynjs.run(synchronousCode,{},function(){
    console.log('done');
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>


-1

मैं ES5 के बाद से कोड का उपयोग कर रहा हूँ।

Promise.wait = function(promiseQueue){
    if( !Array.isArray(promiseQueue) ){
        return Promise.reject('Given parameter is not an array!');
    }

    if( promiseQueue.length === 0 ){
        return Promise.resolve([]);
    }

    return new Promise((resolve, reject) =>{
        let _pQueue=[], _rQueue=[], _readyCount=false;
        promiseQueue.forEach((_promise, idx) =>{
            // Create a status info object
            _rQueue.push({rejected:false, seq:idx, result:null});
            _pQueue.push(Promise.resolve(_promise));
        });

        _pQueue.forEach((_promise, idx)=>{
            let item = _rQueue[idx];
            _promise.then(
                (result)=>{
                    item.resolved = true;
                    item.result = result;
                },
                (error)=>{
                    item.resolved = false;
                    item.result = error;
                }
            ).then(()=>{
                _readyCount++;

                if ( _rQueue.length === _readyCount ) {
                    let result = true;
                    _rQueue.forEach((item)=>{result=result&&item.resolved;});
                    (result?resolve:reject)(_rQueue);
                }
            });
        });
    });
};

उपयोग हस्ताक्षर की तरह ही है Promise.all। प्रमुख अंतर यह है कि Promise.waitअपनी नौकरी खत्म करने के सभी वादों का इंतजार करेंगे।


-1

मुझे पता है कि इस प्रश्न के बहुत सारे उत्तर हैं, और मुझे यकीन है कि (यदि नहीं) सभी सही हैं। हालाँकि इन उत्तरों के तर्क / प्रवाह को समझना मेरे लिए बहुत कठिन था।

इसलिए मैंने मूल कार्यान्वयन को देखा Promise.all(), और मैंने उस तर्क का अनुकरण करने की कोशिश की - यदि एक प्रोमिस विफल नहीं हुआ तो निष्पादन को रोकना नहीं है।

  public promiseExecuteAll(promisesList: Promise<any>[] = []): Promise<{ data: any, isSuccess: boolean }[]>
  {
    let promise: Promise<{ data: any, isSuccess: boolean }[]>;

    if (promisesList.length)
    {
      const result: { data: any, isSuccess: boolean }[] = [];
      let count: number = 0;

      promise = new Promise<{ data: any, isSuccess: boolean }[]>((resolve, reject) =>
      {
        promisesList.forEach((currentPromise: Promise<any>, index: number) =>
        {
          currentPromise.then(
            (data) => // Success
            {
              result[index] = { data, isSuccess: true };
              if (promisesList.length <= ++count) { resolve(result); }
            },
            (data) => // Error
            {
              result[index] = { data, isSuccess: false };
              if (promisesList.length <= ++count) { resolve(result); }
            });
        });
      });
    }
    else
    {
      promise = Promise.resolve([]);
    }

    return promise;
  }

स्पष्टीकरण:
- इनपुट पर लूप करें promisesListऔर प्रत्येक प्रॉमिस को निष्पादित करें।
- वादा किए जाने या अस्वीकार किए जाने पर कोई फर्क नहीं पड़ता: एक के resultअनुसार सरणी में प्रोमिस के परिणाम को सहेजें index। संकल्प / अस्वीकार की स्थिति भी सहेजें ( isSuccess)।
- सभी वादे पूरे होने के बाद, अन्य सभी के परिणाम के साथ एक वादा वापस करें।

उपयोग का उदाहरण:

const p1 = Promise.resolve("OK");
const p2 = Promise.reject(new Error(":-("));
const p3 = Promise.resolve(1000);

promiseExecuteAll([p1, p2, p3]).then((data) => {
  data.forEach(value => console.log(`${ value.isSuccess ? 'Resolve' : 'Reject' } >> ${ value.data }`));
});

/* Output: 
Resolve >> OK
Reject >> :-(
Resolve >> 1000
*/

2
अपने आप को फिर से लागू करने की कोशिश मत करो Promise.all, बहुत सी चीजें हैं जो गलत हो जाएंगी। आपका संस्करण उदाहरण के लिए रिक्त जानकारी को संभालता नहीं है।
बेर्गी

-4

मैं नहीं जानता कि आप किस लायब्रेरी का उपयोग कर रहे हैं, लेकिन अधिकांश में ऑलसेटेड जैसा कुछ है

संपादित करें: ठीक है जब से आप बाहरी पुस्तकालयों के बिना सादे ES6 का उपयोग करना चाहते हैं, ऐसी कोई विधि नहीं है।

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


मैंने अपने प्रश्न को स्पष्ट करने के लिए संपादित किया है - चूंकि ES6 वादों के साथ आता है, मैं एक अन्य पुस्तकालय का उपयोग करने से बचना चाहूंगा जो मुझे लगता है कि बुनियादी कार्यक्षमता है। मुझे लगता है कि उत्तर पाने के लिए एक अच्छी जगह का वादा स्रोत पुस्तकालयों में से एक से कॉपी करना होगा।
नाथन हेगन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.