खोज…
परिचय
एसिंक्रोनस कार्यों को इनलाइन व्यक्त करने के लिए वादों और जनरेटर के शीर्ष पर async
और await
। यह अतुल्यकालिक या कॉलबैक कोड को बनाए रखने के लिए बहुत आसान बनाता है।
async
कीवर्ड वाले कार्य एक Promise
वापस करते हैं, और उस सिंटैक्स के साथ कॉल किया जा सकता है।
एक के अंदर async function
await
कीवर्ड किसी भी लागू किया जा सकता Promise
, और के बाद समारोह शरीर के सभी कारण होगा await
वादा निराकरण के बाद निष्पादित किया जाना है।
वाक्य - विन्यास
- async फ़ंक्शन फू () {
...
asyncCall का इंतजार करें ()
} - async फ़ंक्शन () {...}
- async () => {...}
- (async () => {
const data = asyncCall का इंतजार करें ()
कंसोल.लॉग (डेटा)}) ()
टिप्पणियों
Async फ़ंक्शंस वादों और जनरेटरों पर एक सिंटैक्टिक शुगर है। वे आपके कोड को अधिक पठनीय, बनाए रखने में आसान बनाते हैं, त्रुटियों को कम करने और इंडेंटेशन के कम स्तरों के साथ आसान बनाते हैं।
परिचय
async
रूप में परिभाषित एक फ़ंक्शन एक ऐसा फ़ंक्शन है जो अतुल्यकालिक क्रियाएं कर सकता है लेकिन फिर भी तुल्यकालिक दिखता है। जिस तरह से यह किया है उपयोग कर रहा है await
कीवर्ड समारोह को स्थगित करने के लिए इंतजार कर रहा है, जबकि यह एक वादा संकल्प करने के लिए या अस्वीकार करते हैं।
नोट: Async फ़ंक्शंस ECMAScript 2017 मानक में शामिल किए जाने के लिए ट्रैक पर एक स्टेज 4 ("समाप्त") प्रस्ताव है ।
उदाहरण के लिए, वादा-आधारित Fetch API का उपयोग करना:
async function getJSON(url) {
try {
const response = await fetch(url);
return await response.json();
}
catch (err) {
// Rejections in the promise will get thrown here
console.error(err.message);
}
}
एक async फ़ंक्शन हमेशा एक वादा खुद लौटाता है, इसलिए आप इसे अन्य अतुल्यकालिक कार्यों में उपयोग कर सकते हैं।
एरो फंक्शन स्टाइल
const getJSON = async url => {
const response = await fetch(url);
return await response.json();
}
कम इंडेंटेशन
वादों के साथ:
function doTheThing() {
return doOneThing()
.then(doAnother)
.then(doSomeMore)
.catch(handleErrors)
}
Async फ़ंक्शन के साथ:
async function doTheThing() {
try {
const one = await doOneThing();
const another = await doAnother(one);
return await doSomeMore(another);
} catch (err) {
handleErrors(err);
}
}
ध्यान दें कि वापसी नीचे कैसे है, और शीर्ष पर नहीं है, और आप भाषा के मूल त्रुटि-हैंडलिंग मैकेनिक्स ( try/catch
) का उपयोग करते हैं।
प्रतीक्षा और ऑपरेटर पूर्वता
आपको await
कीवर्ड का उपयोग करते समय ऑपरेटर की पूर्वता को ध्यान में रखना होगा।
कल्पना कीजिए कि हमारे पास एक एसिंक्रोनस फ़ंक्शन है जो एक अन्य एसिंक्रोनस फ़ंक्शन को कॉल करता है, getUnicorn()
जो एक वादा करता है जो क्लास Unicorn
एक उदाहरण के लिए हल करता है। अब हम उस वर्ग की getSize()
पद्धति का उपयोग करके गेंडा का आकार प्राप्त करना चाहते हैं।
निम्नलिखित कोड देखें:
async function myAsyncFunction() {
await getUnicorn().getSize();
}
पहली नजर में यह वैध लगता है, लेकिन ऐसा नहीं है। ऑपरेटर पूर्वता के कारण, यह निम्नलिखित के बराबर है:
async function myAsyncFunction() {
await (getUnicorn().getSize());
}
यहाँ हम वादा वस्तु के getSize()
विधि को कॉल करने का प्रयास करते हैं, जो कि हम नहीं चाहते हैं।
इसके बजाय, हमें यह इंगित करने के लिए कोष्ठक का उपयोग करना चाहिए कि हम पहले गेंडा की प्रतीक्षा करना चाहते हैं, और फिर getSize()
परिणाम की विधि को कॉल करें:
async function asyncFunction() {
(await getUnicorn()).getSize();
}
बेशक। पिछला संस्करण कुछ मामलों में मान्य हो सकता है, उदाहरण के लिए, यदि getUnicorn()
फ़ंक्शन सिंक्रोनस था, लेकिन getSize()
विधि अतुल्यकालिक थी।
वादा के मुकाबले Async फ़ंक्शन
async
फ़ंक्शन Promise
प्रकार को प्रतिस्थापित नहीं Promise
; वे ऐसे भाषा कीवर्ड जोड़ते हैं जो कॉल करने के वादे को आसान बनाते हैं। वे विनिमेय हैं:
async function doAsyncThing() { ... }
function doPromiseThing(input) { return new Promise((r, x) => ...); }
// Call with promise syntax
doAsyncThing()
.then(a => doPromiseThing(a))
.then(b => ...)
.catch(ex => ...);
// Call with await syntax
try {
const a = await doAsyncThing();
const b = await doPromiseThing(a);
...
}
catch(ex) { ... }
कोई भी फ़ंक्शन जो वादों की श्रृंखला का उपयोग await
का उपयोग करके फिर से लिखा जा सकता है:
function newUnicorn() {
return fetch('unicorn.json') // fetch unicorn.json from server
.then(responseCurrent => responseCurrent.json()) // parse the response as JSON
.then(unicorn =>
fetch('new/unicorn', { // send a request to 'new/unicorn'
method: 'post', // using the POST method
body: JSON.stringify({unicorn}) // pass the unicorn to the request body
})
)
.then(responseNew => responseNew.json())
.then(json => json.success) // return success property of response
.catch(err => console.log('Error creating unicorn:', err));
}
समारोह का उपयोग कर लिखा जा सकता है async
/ await
के रूप में इस प्रकार है:
async function newUnicorn() {
try {
const responseCurrent = await fetch('unicorn.json'); // fetch unicorn.json from server
const unicorn = await responseCurrent.json(); // parse the response as JSON
const responseNew = await fetch('new/unicorn', { // send a request to 'new/unicorn'
method: 'post', // using the POST method
body: JSON.stringify({unicorn}) // pass the unicorn to the request body
});
const json = await responseNew.json();
return json.success // return success property of response
} catch (err) {
console.log('Error creating unicorn:', err);
}
}
newUnicorn()
का यह async
संस्करण एक Promise
वापस करने के लिए प्रकट होता है, लेकिन वास्तव में कई await
कीवर्ड थे। प्रत्येक ने एक Promise
वापस किया, इसलिए वास्तव में हमारे पास श्रृंखला के बजाय वादों का एक संग्रह था।
वास्तव में हम एक के रूप में यह सोच सकते हैं function*
प्रत्येक के साथ, जनरेटर await
एक किया जा रहा yield new Promise
। हालांकि, प्रत्येक वादे के परिणाम को फ़ंक्शन जारी रखने के लिए अगले की आवश्यकता होती है। यही कारण है कि फ़ंक्शन पर अतिरिक्त कीवर्ड async
की आवश्यकता होती है (साथ ही वादों को कॉल करते समय await
कीवर्ड) क्योंकि यह जावास्क्रिप्ट को बताता है कि स्वचालित रूप से इस पुनरावृत्ति के लिए एक पर्यवेक्षक बनाता है। async function newUnicorn()
द्वारा लौटाया गया Promise
जब यह पुनरावृत्ति पूर्ण हो जाता है।
व्यावहारिक रूप से, आपको उस पर विचार करने की आवश्यकता नहीं है; await
छुपाता है वादा और async
जनरेटर पुनरावृत्ति छुपाता है।
आप async
फ़ंक्शंस को कॉल कर सकते हैं जैसे कि वे वादे थे, और किसी भी वादे या किसी भी async
फ़ंक्शन का await
। आपको async फ़ंक्शन की await
करने की आवश्यकता नहीं है, जैसे आप एक .then()
बिना एक वादे को निष्पादित कर सकते हैं।
यदि आप उस कोड को तुरंत निष्पादित करना चाहते हैं, तो आप एक async
IIFE का उपयोग भी कर सकते हैं:
(async () => {
await makeCoffee()
console.log('coffee is ready!')
})()
Async प्रतीक्षा के साथ लूपिंग
लूप में async प्रतीक्षा का उपयोग करते समय, आप इन समस्याओं में से कुछ का सामना कर सकते हैं।
यदि आप अभी forEach
अंदर forEach
का उपयोग करने का प्रयास करते हैं, तो यह एक Unexpected token
त्रुटि को फेंक देगा।
(async() => {
data = [1, 2, 3, 4, 5];
data.forEach(e => {
const i = await somePromiseFn(e);
console.log(i);
});
})();
यह इस तथ्य से आता है कि आपने एरो फ़ंक्शन को ब्लॉक के रूप में देखा है। await
कॉलबैक फ़ंक्शन के संदर्भ में होगी, जो कि async
नहीं है।
दुभाषिया हमें उपरोक्त त्रुटि करने से बचाता है, लेकिन यदि आप async
को forEach
कॉलबैक में forEach
हैं तो कोई भी त्रुटि नहीं मिलती है। आपको लगता है कि यह समस्या को हल कर सकता है, लेकिन यह अपेक्षा के अनुरूप काम नहीं करेगा।
उदाहरण:
(async() => {
data = [1, 2, 3, 4, 5];
data.forEach(async(e) => {
const i = await somePromiseFn(e);
console.log(i);
});
console.log('this will print first');
})();
ऐसा इसलिए होता है क्योंकि कॉलबैक async फ़ंक्शन केवल स्वयं को रोक सकता है, न कि पैरेंट async फ़ंक्शन।
आप एक asyncForEach फ़ंक्शन लिख सकते हैं जो एक वादा लौटाता है और फिर आप
await asyncForEach(async (e) => await somePromiseFn(e), data )
कर सकते हैंawait asyncForEach(async (e) => await somePromiseFn(e), data )
मूल रूप से आप एक वादा वापस करते हैं जो सभी कॉलबैक के इंतजार और किए जाने पर हल होता है। लेकिन ऐसा करने के बेहतर तरीके हैं, और वह सिर्फ एक लूप का उपयोग करना है।
आप लूप के लिए या for/while
लूप for-of
उपयोग कर सकते हैं, यह वास्तव में कोई फर्क नहीं पड़ता कि आप कौन सा चुनते हैं।
(async() => {
data = [1, 2, 3, 4, 5];
for (let e of data) {
const i = await somePromiseFn(e);
console.log(i);
}
console.log('this will print last');
})();
लेकिन एक और कैच है। यह समाधान प्रत्येक कॉल के लिए प्रतीक्षा करेगा जब कोई अगले से पहले पुनरावृत्ति करने से पहले somePromiseFn
पर कॉल करेगा।
यह बहुत अच्छा है कि आप वास्तव में चाहते हैं, तो आपके somePromiseFn
आमंत्रण क्रम में निष्पादित किया जाना है लेकिन यदि आप उन्हें समवर्ती चलाना चाहते हैं, तो आप की आवश्यकता होगी await
पर Promise.all
।
(async() => {
data = [1, 2, 3, 4, 5];
const p = await Promise.all(data.map(async(e) => await somePromiseFn(e)));
console.log(...p);
})();
Promise.all
अपने एकमात्र पैरामीटर के रूप में वादों की एक सरणी प्राप्त करता है और एक वादा लौटाता है। जब सरणी में सभी वादों का समाधान हो जाता है, तो लौटा हुआ वादा भी हल हो जाता है। हम उस वादे का await
करते हैं और जब यह हल हो जाता है तो हमारे सभी मूल्य उपलब्ध होते हैं।
उपरोक्त उदाहरण पूरी तरह से चलने योग्य हैं। somePromiseFn
फ़ंक्शन को टाइमआउट के साथ एक async इको फ़ंक्शन के रूप में बनाया जा सकता है। आप कम से कम stage-3
पूर्व निर्धारित और आउटपुट को देखने के साथ बेबल-उत्तर में उदाहरणों को आज़मा सकते हैं।
function somePromiseFn(n) {
return new Promise((res, rej) => {
setTimeout(() => res(n), 250);
});
}
साथ ही साथ एसिंक्रोनस (समानांतर) ऑपरेशन
अक्सर आप समानांतर में अतुल्यकालिक संचालन करना चाहेंगे। वहाँ प्रत्यक्ष सिंटैक्स में इस का समर्थन करता है async
/ await
प्रस्ताव, लेकिन जब से await
एक वादा के लिए इंतजार करेंगे, तो आप में एक साथ कई वादे लपेट कर सकते हैं Promise.all
उनके लिए प्रतीक्षा करने के लिए:
// Not in parallel
async function getFriendPosts(user) {
friendIds = await db.get("friends", {user}, {id: 1});
friendPosts = [];
for (let id in friendIds) {
friendPosts = friendPosts.concat( await db.get("posts", {user: id}) );
}
// etc.
}
यह प्रत्येक मित्र के पदों को क्रमबद्ध रूप से प्राप्त करने के लिए प्रत्येक क्वेरी करेगा, लेकिन उन्हें एक साथ किया जा सकता है:
// In parallel
async function getFriendPosts(user) {
friendIds = await.db.get("friends", {user}, {id: 1});
friendPosts = await Promise.all( friendIds.map(id =>
db.get("posts", {user: id})
);
// etc.
}
यह वादों की एक सरणी बनाने के लिए आईडी की सूची पर लूप करेगा। await
होगा सभी वादे पूरे होने का इंतजार Promise.all
उन्हें एक ही वादे में जोड़ती है, लेकिन वे समानांतर में किए जाते हैं।