खोज…
वाक्य - विन्यास
- नया वादा (/ * निष्पादक फ़ंक्शन: * / फ़ंक्शन (समाधान, अस्वीकार) {})
- वादा करें।
- promise.catch (onRejected)
- Promise.resolve (संकल्प)
- Promise.reject (कारण)
- Promise.all (iterable)
- Promise.race (iterable)
टिप्पणियों
वादे ECMAScript 2015 के विनिर्देश का हिस्सा हैं और ब्राउज़र समर्थन सीमित है, दुनिया भर में जुलाई 2017 तक 88% ब्राउज़र इसका समर्थन कर रहे हैं। निम्न तालिका उन शुरुआती ब्राउज़र संस्करणों का अवलोकन देती है जो वादों के लिए समर्थन प्रदान करते हैं।
क्रोम | धार | फ़ायरफ़ॉक्स | इंटरनेट एक्स्प्लोरर | ओपेरा | ओपेरा मिनी | सफारी | iOS सफारी |
---|---|---|---|---|---|---|---|
32 | 12 | 27 | एक्स | 19 | एक्स | 7.1 | 8 |
ऐसे वातावरण में जो उनका समर्थन नहीं करते हैं, Promise
पॉलीफ़िल किया जा सकता है। तृतीय-पक्ष पुस्तकालय विस्तारित कार्यशीलता भी प्रदान कर सकते हैं, जैसे कॉलबैक फ़ंक्शन के स्वचालित "प्रॉमिसिफिकेशन" या progress
जैसे अतिरिक्त तरीकों को notify
।
प्रॉमिस / ए + मानक वेबसाइट 1.0 और 1.1 अनुपालन कार्यान्वयन की एक सूची प्रदान करती है। A + मानक पर आधारित वादा कॉलबैक को हमेशा अतुल्यकालिक रूप से इवेंट लूप में माइक्रो-मास्क के रूप में निष्पादित किया जाता है।
चैनिंग का वादा
वादे का then
तरीका एक नया वादा लौटाता है।
const promise = new Promise(resolve => setTimeout(resolve, 5000));
promise
// 5 seconds later
.then(() => 2)
// returning a value from a then callback will cause
// the new promise to resolve with this value
.then(value => { /* value === 2 */ });
then
कॉलबैक से एक Promise
लौटाकर इसे वादा श्रृंखला में जोड़ा जाएगा।
function wait(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
const p = wait(5000).then(() => wait(4000)).then(() => wait(1000));
p.then(() => { /* 10 seconds have passed */ });
एक catch
अस्वीकार किए गए वादे को पुनर्प्राप्त करने की अनुमति देता है, एक try
/ catch
स्टेटमेंट में कैसे catch
है। किसी भी श्रृंखलित then
बाद एक catch
से हल हो गई मूल्य का उपयोग कर अपने संकल्प हैंडलर निष्पादित करेंगे catch
।
const p = new Promise(resolve => {throw 'oh no'});
p.catch(() => 'oh yes').then(console.log.bind(console)); // outputs "oh yes"
यदि श्रृंखला के मध्य में कोई catch
या reject
हैंडलर नहीं हैं, तो अंत में एक catch
श्रृंखला में किसी भी अस्वीकृति को catch
लेगा:
p.catch(() => Promise.reject('oh yes'))
.then(console.log.bind(console)) // won't be called
.catch(console.error.bind(console)); // outputs "oh yes"
कुछ अवसरों पर, आप फ़ंक्शन के निष्पादन को "शाखा" करना चाह सकते हैं। आप शर्त के आधार पर एक फ़ंक्शन से विभिन्न वादों को वापस करके कर सकते हैं। बाद में कोड में, आप इन सभी शाखाओं को एक में मर्ज कर सकते हैं उन पर अन्य कार्यों को कॉल करने और / या एक ही स्थान पर सभी त्रुटियों को संभालने के लिए।
promise
.then(result => {
if (result.condition) {
return handlerFn1()
.then(handlerFn2);
} else if (result.condition2) {
return handlerFn3()
.then(handlerFn4);
} else {
throw new Error("Invalid result");
}
})
.then(handlerFn5)
.catch(err => {
console.error(err);
});
इस प्रकार, कार्यों का निष्पादन क्रम इस तरह दिखता है:
promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
| ^
V |
-> handlerFn3 -> handlerFn4 -^
जो भी शाखा हो सकती है, उस पर एकल catch
की त्रुटि होगी।
परिचय
एक Promise
ऑब्जेक्ट एक ऑपरेशन का प्रतिनिधित्व करता है जिसने उत्पादन किया है या अंततः एक मूल्य का उत्पादन करेगा । वादे असंगत काम के परिणाम (संभवतः लंबित) को लपेटने का एक मजबूत तरीका प्रदान करते हैं, गहरी नेस्टेड कॉलबैक (" कॉलबैक नरक " के रूप में जाना जाता है) की समस्या को कम करता है।
राज्यों और नियंत्रण प्रवाह
एक वादा तीन राज्यों में से एक में हो सकता है:
- लंबित - अंतर्निहित आपरेशन अभी तक पूरा नहीं किया है, और वादा पूरा लंबित है।
- पूरा किया - ऑपरेशन समाप्त हो गया है, और एक मूल्य के साथ वादा पूरा हुआ है। यह एक तुल्यकालिक फ़ंक्शन से मान लौटाने के लिए अनुरूप है।
- खारिज - ऑपरेशन के दौरान एक त्रुटि हुई है, और एक कारण के साथ वादा खारिज कर दिया गया है। यह एक तुल्यकालिक फ़ंक्शन में त्रुटि फेंकने के लिए अनुरूप है।
किसी वादे का निपटारा (या हल ) तब किया जाता है जब वह या तो पूरा हो जाए या खारिज हो जाए। एक बार एक वादा तय हो जाने के बाद, यह अपरिवर्तनीय हो जाता है, और इसकी स्थिति नहीं बदल सकती है। किसी वादे के then
और catch
तरीकों का उपयोग कॉलबैक को संलग्न करने के लिए किया जा सकता है जो कि निपटान होने पर निष्पादित होता है। इन कॉलबैक को क्रमशः पूर्ति मूल्य और अस्वीकृति के कारण लगाया जाता है।
उदाहरण
const promise = new Promise((resolve, reject) => {
// Perform some work (possibly asynchronous)
// ...
if (/* Work has successfully finished and produced "value" */) {
resolve(value);
} else {
// Something went wrong because of "reason"
// The reason is traditionally an Error object, although
// this is not required or enforced.
let reason = new Error(message);
reject(reason);
// Throwing an error also rejects the promise.
throw reason;
}
});
पूर्ति और अस्वीकृति कॉलबैक को संलग्न करने के लिए then
और catch
तरीकों का उपयोग किया जा सकता है:
promise.then(value => {
// Work has completed successfully,
// promise has been fulfilled with "value"
}).catch(reason => {
// Something went wrong,
// promise has been rejected with "reason"
});
नोट: कॉलिंग promise.then(...)
और promise.catch(...)
एक ही वादे पर एक Uncaught exception in Promise
परिणाम हो सकता है यदि कोई त्रुटि होती है, या तो वादे को निष्पादित करते समय या कॉलबैक में से एक के अंदर, तो पसंदीदा तरीका वादा पिछले द्वारा दिया पर अगले श्रोता संलग्न करने के लिए किया जाएगा then
/ catch
।
वैकल्पिक रूप से, दोनों कॉलबैक को then
सिंगल कॉल में संलग्न किया जा सकता है:
promise.then(onFulfilled, onRejected);
पहले से ही निपटाए गए वादे के लिए कॉलबैक को संलग्न करना तुरंत उन्हें माइक्रोटस्क कतार में रख देगा, और उन्हें "जितनी जल्दी हो सके" लागू किया जाएगा (यानी वर्तमान में निष्पादित स्क्रिप्ट के तुरंत बाद)। कॉलबैक को संलग्न करने से पहले वादे की स्थिति की जांच करना आवश्यक नहीं है, इसके विपरीत कई अन्य घटना-क्रियान्वयन कार्यान्वयन के साथ।
देरी समारोह कॉल
setTimeout()
विधि एक फ़ंक्शन को कॉल करती है या एक निर्दिष्ट संख्या में मिलीसेकंड के बाद एक अभिव्यक्ति का मूल्यांकन करती है। यह एक अतुल्यकालिक ऑपरेशन को प्राप्त करने का एक तुच्छ तरीका भी है।
इस उदाहरण में wait
फ़ंक्शन को कॉल करने के बाद पहले तर्क के रूप में निर्दिष्ट समय के बाद वादे को हल किया जाता है:
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
wait(5000).then(() => {
console.log('5 seconds have passed...');
});
कई समवर्ती वादों की प्रतीक्षा है
Promise.all()
स्थैतिक विधि वादों के एक चलने योग्य (जैसे एक Array
) को स्वीकार करती है और एक नया वादा लौटाती है, जो हल करने योग्य सभी वादों को हल करने पर हल करती है, या अस्वीकार कर देती है यदि पुनरावृत्त में से कम से कम एक वादे को अस्वीकार कर दिया है।
// wait "millis" ms, then resolve with "value"
function resolve(value, milliseconds) {
return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}
// wait "millis" ms, then reject with "reason"
function reject(reason, milliseconds) {
return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
resolve(3, 7000)
]).then(values => console.log(values)); // outputs "[1, 2, 3]" after 7 seconds.
Promise.all([
resolve(1, 5000),
reject('Error!', 6000),
resolve(2, 7000)
]).then(values => console.log(values)) // does not output anything
.catch(reason => console.log(reason)); // outputs "Error!" after 6 seconds.
चलने योग्य में गैर-वादा मूल्य "प्रॉमिस" हैं ।
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
{ hello: 3 }
])
.then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds
विनाशकारी असाइनमेंट कई वादों से परिणाम प्राप्त करने में मदद कर सकता है।
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
resolve(3, 7000)
])
.then(([result1, result2, result3]) => {
console.log(result1);
console.log(result2);
console.log(result3);
});
कई समवर्ती वादों में से पहली प्रतीक्षा कर रहा है
Promise.race()
स्थैतिक विधि वादों के एक चलने योग्य को स्वीकार करता है और एक नया वादा करता है जो हल करता है या अस्वीकार करता है जैसे ही पुनरावृति में वादों में से पहला हल या अस्वीकार कर दिया गया है।
// wait "milliseconds" milliseconds, then resolve with "value"
function resolve(value, milliseconds) {
return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}
// wait "milliseconds" milliseconds, then reject with "reason"
function reject(reason, milliseconds) {
return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}
Promise.race([
resolve(1, 5000),
resolve(2, 3000),
resolve(3, 1000)
])
.then(value => console.log(value)); // outputs "3" after 1 second.
Promise.race([
reject(new Error('bad things!'), 1000),
resolve(2, 2000)
])
.then(value => console.log(value)) // does not output anything
.catch(error => console.log(error.message)); // outputs "bad things!" after 1 second
"वादा" मूल्यों
वादों में मूल्यों को लपेटने के लिए Promise.resolve
स्थिर विधि का उपयोग किया जा सकता है।
let resolved = Promise.resolve(2);
resolved.then(value => {
// immediately invoked
// value === 2
});
यदि value
पहले से ही एक वादा है, तो Promise.resolve
बस इसे फिर से शुरू करता है।
let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
let two = Promise.resolve(one);
two.then(value => {
// 1 second has passed
// value === 2
});
वास्तव में, value
किसी भी "तब" हो सकता है (एक then
विधि को परिभाषित करने वाली वस्तु जो एक युक्ति-संगत वादे की तरह पर्याप्त रूप से काम करती है)। यह Promise.resolve
को अविश्वसनीय तृतीय-पक्ष ऑब्जेक्ट्स को विश्वसनीय प्रथम-पक्ष वादों में परिवर्तित करने की अनुमति देता है।
let resolved = Promise.resolve({
then(onResolved) {
onResolved(2);
}
});
resolved.then(value => {
// immediately invoked
// value === 2
});
Promise.reject
स्थिर विधि एक वादा देता है जो दिए गए reason
साथ तुरंत अस्वीकार कर देता reason
।
let rejected = Promise.reject("Oops!");
rejected.catch(reason => {
// immediately invoked
// reason === "Oops!"
});
कॉलबैक के साथ "प्रॉमिसिंग" कार्य
एक फ़ंक्शन को देखते हुए जो एक नोड-शैली कॉलबैक स्वीकार करता है,
fooFn(options, function callback(err, result) { ... });
आप इसे इस तरह से वादा कर सकते हैं (इसे वादा-आधारित फ़ंक्शन में बदल सकते हैं) :
function promiseFooFn(options) {
return new Promise((resolve, reject) =>
fooFn(options, (err, result) =>
// If there's an error, reject; otherwise resolve
err ? reject(err) : resolve(result)
)
);
}
इस फ़ंक्शन का उपयोग इस प्रकार किया जा सकता है:
promiseFooFn(options).then(result => {
// success!
}).catch(err => {
// error!
});
अधिक सामान्य तरीके से, यहां किसी भी कॉलबैक-शैली फ़ंक्शन का प्रचार करने का तरीका बताया गया है:
function promisify(func) {
return function(...args) {
return new Promise((resolve, reject) => {
func(...args, (err, result) => err ? reject(err) : resolve(result));
});
}
}
इसका उपयोग इस तरह किया जा सकता है:
const fs = require('fs');
const promisedStat = promisify(fs.stat.bind(fs));
promisedStat('/foo/bar')
.then(stat => console.log('STATE', stat))
.catch(err => console.log('ERROR', err));
गलती संभालना
वादों से फेंकी गई त्रुटियों को then
पारित किए गए दूसरे पैरामीटर ( reject
) द्वारा नियंत्रित किया जाता है या catch
लिए पारित हैंडलर द्वारा:
throwErrorAsync()
.then(null, error => { /* handle error here */ });
// or
throwErrorAsync()
.catch(error => { /* handle error here */ });
चेनिंग
आप एक वादा श्रृंखला है तो एक त्रुटि का कारण होगा resolve
संचालकों को छोड़ दिया हो:
throwErrorAsync()
.then(() => { /* never called */ })
.catch(error => { /* handle error here */ });
वही आपके then
कार्यों पर लागू होता है। यदि कोई resolve
हैंडलर अपवाद फेंकता है, तो अगले reject
हैंडलर को आमंत्रित किया जाएगा:
doSomethingAsync()
.then(result => { throwErrorSync(); })
.then(() => { /* never called */ })
.catch(error => { /* handle error from throwErrorSync() */ });
एक त्रुटि हैंडलर एक नया वादा लौटाता है, जिससे आप एक वादा श्रृंखला जारी रख सकते हैं। त्रुटि हैंडलर द्वारा दिए गए वादे को हैंडलर द्वारा लौटाए गए मूल्य के साथ हल किया जाता है:
throwErrorAsync()
.catch(error => { /* handle error here */; return result; })
.then(result => { /* handle result here */ });
आप त्रुटि को फिर से फेंककर एक वादा श्रृंखला के नीचे एक त्रुटि दे सकते हैं:
throwErrorAsync()
.catch(error => {
/* handle error from throwErrorAsync() */
throw error;
})
.then(() => { /* will not be called if there's an error */ })
.catch(error => { /* will get called with the same error */ });
एक setTimeout
कॉलबैक के अंदर throw
स्टेटमेंट को लपेटकर वादे द्वारा नियंत्रित न होने वाले अपवाद को फेंकना संभव है:
new Promise((resolve, reject) => {
setTimeout(() => { throw new Error(); });
});
यह काम करता है क्योंकि वादे असंगत रूप से फेंके गए अपवादों को संभाल नहीं सकते।
अकारण अस्वीकार
यदि किसी वादे में catch
ब्लॉक नहीं होता है या हैंडलर reject
नहीं किया जाता है, तो एक त्रुटि को चुपचाप अनदेखा कर दिया जाएगा:
throwErrorAsync()
.then(() => { /* will not be called */ });
// error silently ignored
इसे रोकने के लिए, हमेशा catch
ब्लॉक का उपयोग करें:
throwErrorAsync()
.then(() => { /* will not be called */ })
.catch(error => { /* handle error*/ });
// or
throwErrorAsync()
.then(() => { /* will not be called */ }, error => { /* handle error*/ });
वैकल्पिक रूप से, किसी भी अनचाहे अस्वीकार किए गए वादे को पकड़ने के लिए unhandledrejection
इवेंट की सदस्यता लें:
window.addEventListener('unhandledrejection', event => {});
कुछ वादे उनके निर्माण समय की तुलना में बाद में उनकी अस्वीकृति को संभाल सकते हैं। जब भी इस तरह के वादे को संभाला जाता है, तो rejectionhandled
घटना को निकाल दिया जाता है:
window.addEventListener('unhandledrejection', event => console.log('unhandled'));
window.addEventListener('rejectionhandled', event => console.log('handled'));
var p = Promise.reject('test');
setTimeout(() => p.catch(console.log), 1000);
// Will print 'unhandled', and after one second 'test' and 'handled'
event
तर्क में अस्वीकृति के बारे में जानकारी है। event.reason
त्रुटि ऑब्जेक्ट है और event.promise
वादा ऑब्जेक्ट है जो इवेंट का कारण बनता है।
Nodejs में rejectionhandled
और unhandledrejection
इवेंट्स को rejectionHandled
और unhandledRejection
rejectionHandled
कहा जाता process
, क्रमशः, और एक अलग हस्ताक्षर है:
process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});
reason
तर्क त्रुटि वस्तु है और promise
तर्क वादा उद्देश्य यह है कि आग में घटना की वजह से करने के लिए एक संदर्भ है।
इन unhandledrejection
और rejectionhandled
घटनाओं के उपयोग को केवल डीबगिंग उद्देश्यों के लिए माना जाना चाहिए। आमतौर पर, सभी वादों को उनके अस्वीकार को संभालना चाहिए।
नोट: वर्तमान में, केवल क्रोम 49+ और Node.js समर्थन unhandledrejection
और rejectionhandled
घटनाओं।
चेतावनियां
साथ चेनिंग fulfill
और reject
then(fulfill, reject)
फ़ंक्शन (दोनों मापदंडों के साथ null
नहीं) में अद्वितीय और जटिल व्यवहार होता है, और इसका उपयोग तब तक नहीं किया जाना चाहिए जब तक कि आपको यह पता न चले कि यह कैसे काम करता है।
यदि इनपुट में से किसी एक के लिए null
दिए जाने पर फ़ंक्शन अपेक्षा के अनुसार काम करता है:
// the following calls are equivalent
promise.then(fulfill, null)
promise.then(fulfill)
// the following calls are also equivalent
promise.then(null, reject)
promise.catch(reject)
हालाँकि, यह अनूठा व्यवहार अपनाता है जब दोनों इनपुट दिए जाते हैं:
// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.then(fulfill).catch(reject)
// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.catch(reject).then(fulfill)
then(fulfill, reject)
फ़ंक्शन ऐसा लगता है कि यह then(fulfill).catch(reject)
लिए एक शॉर्टकट है, लेकिन यह नहीं है, और यदि परस्पर विनिमय का उपयोग किया जाता है, तो समस्या पैदा होगी। ऐसा ही एक समस्या यह है कि है reject
हैंडलर से त्रुटियों को संभाल नहीं करता है fulfill
हैंडलर। यहाँ है क्या होगा:
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }, // error in the fulfill handler
error => { /* this is not called! */ });
उपरोक्त कोड परिणाम को अस्वीकार कर देगा क्योंकि त्रुटि प्रचारित है। इसकी तुलना निम्नलिखित कोड से करें, जिसके परिणामस्वरूप एक पूरा हुआ वादा:
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }) // error in the fulfill handler
.catch(error => { /* handle error */ });
इसी तरह की समस्या तब होती है जब catch(reject).then(fulfill)
रिजेक्ट then(fulfill, reject)
के साथ एक-दूसरे का उपयोग करते हैं। then(fulfill, reject)
वादों के बजाय पूर्ण किए गए वादों को छोड़कर।
फ़ंक्शन से सिंक्रनाइज़ेशन फेंकना चाहिए जो एक वादा वापस करना चाहिए
इस तरह एक समारोह की कल्पना करो:
function foo(arg) {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
यदि इस तरह के फ़ंक्शन का उपयोग वादा श्रृंखला के बीच में किया जाता है, तो स्पष्ट रूप से कोई समस्या नहीं है:
makeSomethingAsync().
.then(() => foo('unexpectedValue'))
.catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here
हालाँकि, यदि समान फ़ंक्शन को एक वादा श्रृंखला के बाहर कहा जाता है, तो त्रुटि इसके द्वारा नियंत्रित नहीं की जाएगी और आवेदन करने के लिए फेंक दी जाएगी:
foo('unexpectedValue') // <-- error will be thrown, so the application will crash
.then(makeSomethingAsync) // <-- will not run
.catch(err => console.log(err)) // <-- will not catch
2 संभावित वर्कअराउंड हैं:
त्रुटि के साथ अस्वीकार किए गए वादे को वापस करें
फेंकने के बजाय, इस प्रकार करें:
function foo(arg) {
if (arg === 'unexepectedValue') {
return Promise.reject(new Error('UnexpectedValue'))
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
अपने कार्य को एक वादा श्रृंखला में लपेटें
जब आप पहले से ही एक वादा श्रृंखला के अंदर हैं तो आपका throw
स्टेटमेंट ठीक से पकड़ा जाएगा:
function foo(arg) {
return Promise.resolve()
.then(() => {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
})
}
तुल्यकालिक और अतुल्यकालिक संचालन को फिर से संगठित करना
कुछ मामलों में आप कोड शाखाओं में पुनरावृत्ति को रोकने के लिए एक वादा के अंदर एक तुल्यकालिक ऑपरेशन लपेटना चाह सकते हैं। इस उदाहरण को लें:
if (result) { // if we already have a result
processResult(result); // process it
} else {
fetchResult().then(processResult);
}
उपरोक्त कोड की सिंक्रोनस और एसिंक्रोनस शाखाओं को एक वादे के अंदर सिंक्रोनस ऑपरेशन लपेटकर अनावश्यक रूप से समेटा जा सकता है:
var fetch = result
? Promise.resolve(result)
: fetchResult();
fetch.then(processResult);
जब एक अतुल्यकालिक कॉल के परिणाम को कैशिंग करते हैं, तो परिणाम के बजाय वादे को कैश करना बेहतर होता है। यह सुनिश्चित करता है कि कई समानांतर अनुरोधों को हल करने के लिए केवल एक अतुल्यकालिक ऑपरेशन की आवश्यकता होती है।
त्रुटि की स्थिति आने पर कैश्ड मानों को अमान्य करने पर ध्यान दिया जाना चाहिए।
// A resource that is not expected to change frequently
var planets = 'http://swapi.co/api/planets/';
// The cached promise, or null
var cachedPromise;
function fetchResult() {
if (!cachedPromise) {
cachedPromise = fetch(planets)
.catch(function (e) {
// Invalidate the current result to retry on the next fetch
cachedPromise = null;
// re-raise the error to propagate it to callers
throw e;
});
}
return cachedPromise;
}
जंजीर वादों के लिए एक सरणी कम करें
तत्वों की सूची से अतुल्यकालिक कार्यों के अनुक्रम को उत्पन्न करने के लिए यह डिज़ाइन पैटर्न उपयोगी है।
इसके दो प्रकार हैं:
- "तब" कमी, जो एक श्रृंखला का निर्माण करती है जो तब तक जारी रहती है जब तक श्रृंखला सफलता का अनुभव करती है।
- "कैच" कटौती, जो एक श्रृंखला का निर्माण करती है जो तब तक जारी रहती है जब तक श्रृंखला त्रुटि का अनुभव नहीं करती है।
"फिर" में कमी
पैटर्न का यह संस्करण एक .then()
श्रृंखला बनाता है, और इसका उपयोग एनिमेशन का पीछा करने या निर्भर HTTP अनुरोधों के अनुक्रम बनाने के लिए किया जा सकता है।
[1, 3, 5, 7, 9].reduce((seq, n) => {
return seq.then(() => {
console.log(n);
return new Promise(res => setTimeout(res, 1000));
});
}, Promise.resolve()).then(
() => console.log('done'),
(e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals
स्पष्टीकरण:
- हम फोन
.reduce()
एक स्रोत सरणी पर, और प्रदान करते हैंPromise.resolve()
एक प्रारंभिक मूल्य के रूप में। - कम किया गया प्रत्येक तत्व प्रारंभिक मूल्य में एक
.then()
जोड़ देगा। -
reduce()
का उत्पाद Promise.resolve () होगा। फिर (...) तब (...)। - हम मैन्युअल रूप से
.then(successHandler, errorHandler)
को.then(successHandler, errorHandler)
बादsuccessHandler
को निष्पादित करने के लिए एक बार सभी पिछले चरणों को हल कर लेते हैं। यदि कोई भी कदम विफल होना था, तोerrorHandler
निष्पादित करेगा।
नोट: "तब" कमी Promise.all()
का एक क्रमिक प्रतिरूप है।
"पकड़" कमी
पैटर्न का यह संस्करण एक .catch()
श्रृंखला बनाता है और क्रमिक रूप से कुछ सर्वरों के लिए वेब सर्वर के सेट को .catch()
लिए इस्तेमाल किया जा सकता है जब तक कि एक कार्यशील सर्वर नहीं मिलता है।
var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
return seq.catch(() => {
console.log(n);
if(n === working_resource) { // 5 is working
return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
} else { // all other values are not working
return new Promise((resolve, reject) => setTimeout(reject, 1000));
}
});
}, Promise.reject()).then(
(n) => console.log('success at: ' + n),
() => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals
स्पष्टीकरण:
- हम फोन
.reduce()
एक स्रोत सरणी पर, और प्रदान करते हैंPromise.reject()
एक प्रारंभिक मूल्य के रूप में। - कम किया गया प्रत्येक तत्व प्रारंभिक मूल्य में एक
.catch()
जोड़ देगा। -
reduce()
का उत्पादPromise.reject().catch(...).catch(...)
। - हम कम करने के बाद
.then(successHandler, errorHandler)
को मैन्युअल रूप से अपेंड.then(successHandler, errorHandler)
successHandler
के लिए पिछले किसी भी चरण को हल करने के बादsuccessHandler
को निष्पादित करें। यदि सभी चरणों को विफल होना था, तोerrorHandler
निष्पादित करेगा।
नोट: "कैच" की कमी Promise.any()
अनुक्रमिक समकक्ष है (जैसा कि bluebird.js
में लागू किया गया है, लेकिन वर्तमान में देशी ईसीएमएस्क्रिप्ट में नहीं है)।
वादों के साथ आगे बढ़ें
किसी फ़ंक्शन ( cb
) को प्रभावी ढंग से लागू करना संभव है जो कि किसी सरणी के प्रत्येक तत्व के लिए एक वादा लौटाता है, प्रत्येक तत्व के साथ प्रतीक्षा की जाती है जब तक कि पिछले तत्व को संसाधित नहीं किया जाता है।
function promiseForEach(arr, cb) {
var i = 0;
var nextPromise = function () {
if (i >= arr.length) {
// Processing finished.
return;
}
// Process next function. Wrap in `Promise.resolve` in case
// the function does not return a promise
var newPromise = Promise.resolve(cb(arr[i], i));
i++;
// Chain to finish processing.
return newPromise.then(nextPromise);
};
// Kick off the chain.
return Promise.resolve().then(nextPromise);
};
यह उपयोगी हो सकता है यदि आपको कुशलतापूर्वक हजारों वस्तुओं को संसाधित करने की आवश्यकता होती है, तो एक बार में। वादों को बनाने के for
एक नियमित रूप for
लूप का उपयोग करना उन सभी को एक साथ पैदा करेगा और रैम की एक महत्वपूर्ण राशि लेगा।
अंत में () के साथ सफाई प्रदर्शन
वर्तमान में एक प्रस्ताव है (अभी तक ECMAScript मानक का हिस्सा नहीं) वादे को पूरा करने के लिए एक finally
कॉलबैक जोड़ने के लिए, चाहे वह वादा पूरा हो या खारिज कर दिया गया हो। शब्दार्थ, यह try
ब्लॉक के finally
खंड के समान है।
आप आमतौर पर सफाई के लिए इस कार्यक्षमता का उपयोग करेंगे:
var loadingData = true;
fetch('/data')
.then(result => processData(result.data))
.catch(error => console.error(error))
.finally(() => {
loadingData = false;
});
यह नोट करना महत्वपूर्ण है कि finally
कॉलबैक वादे की स्थिति को प्रभावित नहीं करता है। इससे कोई फर्क नहीं पड़ता कि यह किस मूल्य पर लौटता है, वादा पूरा / अस्वीकृत राज्य में रहता है जो पहले था। तो ऊपर दिए गए उदाहरण में वादे को processData(result.data)
के रिटर्न मूल्य के साथ हल किया जाएगा, भले ही finally
कॉलबैक undefined
लौटे।
मानकीकरण प्रक्रिया अभी भी प्रगति पर है, आपके वादों के क्रियान्वयन की सबसे अधिक संभावना है कि finally
कॉलबैक बॉक्स का समर्थन नहीं करेगा। सिंक्रोनस कॉलबैक के लिए आप इस कार्यक्षमता को पॉलीफ़िल के साथ जोड़ सकते हैं:
if (!Promise.prototype.finally) {
Promise.prototype.finally = function(callback) {
return this.then(result => {
callback();
return result;
}, error => {
callback();
throw error;
});
};
}
अतुल्यकालिक एपीआई अनुरोध
यह एक सरल GET
API कॉल का एक उदाहरण है जो अपनी अतुल्यकालिक कार्यक्षमता का लाभ उठाने के वादे में लिपटा हुआ है।
var get = function(path) {
return new Promise(function(resolve, reject) {
let request = new XMLHttpRequest();
request.open('GET', path);
request.onload = resolve;
request.onerror = reject;
request.send();
});
};
निम्नलिखित onload
और onerror
कार्यों का उपयोग करके अधिक मजबूत त्रुटि हैंडलिंग की जा सकती है।
request.onload = function() {
if (this.status >= 200 && this.status < 300) {
if(request.response) {
// Assuming a successful call returns JSON
resolve(JSON.parse(request.response));
} else {
resolve();
} else {
reject({
'status': this.status,
'message': request.statusText
});
}
};
request.onerror = function() {
reject({
'status': this.status,
'message': request.statusText
});
};
ES2017 async / प्रतीक्षा का उपयोग करना
ऊपर का एक ही उदाहरण, छवि लोड करना , async फ़ंक्शंस का उपयोग करके लिखा जा सकता है। यह अपवाद हैंडलिंग के लिए सामान्य try/catch
विधि का उपयोग करने की भी अनुमति देता है।
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', () => {
reject(new Error(`Failed to load ${url}`));
});
img.src = url;
});
}
(async () => {
// load /image.png and append to #image-holder, otherwise throw error
try {
let img = await loadImage('http://example.com/image.png');
document.getElementById('image-holder').appendChild(img);
}
catch (error) {
console.error(error);
}
})();