புரோஹோஸ்டர் > Блог > இணைய செய்தி > உதாரணங்களைப் பயன்படுத்தி ஜாவாஸ்கிரிப்டில் Async/Await ஐப் பார்க்கலாம்
உதாரணங்களைப் பயன்படுத்தி ஜாவாஸ்கிரிப்டில் Async/Await ஐப் பார்க்கலாம்
கட்டுரையின் ஆசிரியர் ஜாவாஸ்கிரிப்டில் ஒத்திசைவு/காத்திருப்பதற்கான உதாரணங்களை ஆய்வு செய்கிறார். ஒட்டுமொத்தமாக, ஒத்திசைவற்ற குறியீட்டை எழுத Async/Await ஒரு வசதியான வழியாகும். இந்த அம்சம் தோன்றுவதற்கு முன்பு, அத்தகைய குறியீடு கால்பேக்குகள் மற்றும் வாக்குறுதிகளைப் பயன்படுத்தி எழுதப்பட்டது. அசல் கட்டுரையின் ஆசிரியர் பல்வேறு எடுத்துக்காட்டுகளை பகுப்பாய்வு செய்வதன் மூலம் Async/Await இன் நன்மைகளை வெளிப்படுத்துகிறார்.
நாங்கள் நினைவூட்டுகிறோம்:"Habr" இன் அனைத்து வாசகர்களுக்கும் - "Habr" விளம்பரக் குறியீட்டைப் பயன்படுத்தி எந்த Skillbox படிப்பிலும் சேரும்போது 10 ரூபிள் தள்ளுபடி.
Skillbox பரிந்துரைக்கிறது: கல்வி ஆன்லைன் படிப்பு "ஜாவா டெவலப்பர்".
கோரிக்கை
கால்பேக் என்பது காலவரையின்றி தாமதமாகும் ஒரு செயல்பாடு. முன்னதாக, முடிவை உடனடியாகப் பெற முடியாத குறியீட்டின் பகுதிகளில் கால்பேக்குகள் பயன்படுத்தப்பட்டன.
Node.js இல் ஒரு கோப்பை ஒத்திசைவின்றி வாசிப்பதற்கான எடுத்துக்காட்டு இங்கே:
நீங்கள் ஒரே நேரத்தில் பல ஒத்திசைவற்ற செயல்பாடுகளைச் செய்ய வேண்டியிருக்கும் போது சிக்கல்கள் எழுகின்றன. இந்த சூழ்நிலையை கற்பனை செய்து பார்க்கலாம்: Arfat பயனர் தரவுத்தளத்திற்கு ஒரு கோரிக்கை செய்யப்படுகிறது, நீங்கள் அதன் profile_img_url புலத்தைப் படித்து, someserver.com சேவையகத்திலிருந்து ஒரு படத்தைப் பதிவிறக்க வேண்டும்.
பதிவிறக்கிய பிறகு, படத்தை வேறொரு வடிவத்திற்கு மாற்றுவோம், உதாரணமாக PNG இலிருந்து JPEG க்கு. மாற்றம் வெற்றிகரமாக இருந்தால், பயனரின் மின்னஞ்சலுக்கு ஒரு கடிதம் அனுப்பப்படும். அடுத்து, நிகழ்வைப் பற்றிய தகவல்கள் transformations.log கோப்பில் உள்ளிடப்பட்டு, தேதியைக் குறிக்கும்.
குறியீட்டின் இறுதிப் பகுதியில் கால்பேக்குகளின் ஒன்றுடன் ஒன்று மற்றும் அதிக எண்ணிக்கையிலான }) கவனம் செலுத்துவது மதிப்பு. இது கால்பேக் ஹெல் அல்லது பிரமிட் ஆஃப் டூம் என்று அழைக்கப்படுகிறது.
இந்த முறையின் தீமைகள் வெளிப்படையானவை:
இந்த குறியீடு படிக்க கடினமாக உள்ளது.
பிழைகளைக் கையாள்வது கடினம், இது பெரும்பாலும் மோசமான குறியீட்டின் தரத்திற்கு வழிவகுக்கிறது.
இந்தச் சிக்கலைத் தீர்க்க, ஜாவாஸ்கிரிப்ட்டில் வாக்குறுதிகள் சேர்க்கப்பட்டன. கால்பேக்குகளின் ஆழமான கூடுகளை .பின் என்ற வார்த்தையுடன் மாற்ற அவை உங்களை அனுமதிக்கின்றன.
வாக்குறுதிகளின் நேர்மறையான அம்சம் என்னவென்றால், அவை குறியீட்டை இடமிருந்து வலமாகப் படிக்காமல் மேலிருந்து கீழாகப் படிக்கக்கூடியதாக ஆக்குகிறது. இருப்பினும், வாக்குறுதிகளுக்கு அவற்றின் சிக்கல்களும் உள்ளன:
நீங்கள் .பின் நிறைய சேர்க்க வேண்டும்.
முயற்சி/பிடிப்பதற்குப் பதிலாக, எல்லாப் பிழைகளையும் கையாள .catch பயன்படுத்தப்படுகிறது.
ஒரு வளையத்திற்குள் பல வாக்குறுதிகளுடன் வேலை செய்வது எப்போதும் வசதியானது அல்ல; சில சந்தர்ப்பங்களில், அவை குறியீட்டை சிக்கலாக்குகின்றன.
கடைசி புள்ளியின் அர்த்தத்தைக் காட்டும் ஒரு சிக்கல் இங்கே உள்ளது.
0 முதல் 10 வரையிலான எண்களின் வரிசையை சீரற்ற இடைவெளியில் (0–n வினாடிகள்) அச்சிடுவதற்கு ஒரு லூப் உள்ளது என்று வைத்துக்கொள்வோம். வாக்குறுதிகளைப் பயன்படுத்தி, எண்கள் 0 முதல் 10 வரையிலான வரிசையில் அச்சிடப்படும் வகையில் இந்த வளையத்தை மாற்ற வேண்டும். எனவே, பூஜ்ஜியத்தை அச்சிட 6 வினாடிகளும், ஒன்றை அச்சிட 2 வினாடிகளும் எடுத்தால், முதலில் பூஜ்ஜியத்தை அச்சிட வேண்டும், பின்னர் அச்சிடுவதற்கான கவுண்டவுன் தொடங்கும்.
நிச்சயமாக, இந்தச் சிக்கலைத் தீர்க்க நாங்கள் Async/Await அல்லது .sort ஐப் பயன்படுத்த மாட்டோம். ஒரு எடுத்துக்காட்டு தீர்வு முடிவில் உள்ளது.
ஒத்திசைவு செயல்பாடுகள்
ES2017 (ES8) இல் ஒத்திசைவு செயல்பாடுகளைச் சேர்ப்பது வாக்குறுதிகளுடன் பணிபுரியும் பணியை எளிதாக்கியது. ஒத்திசைவு செயல்பாடுகள் வாக்குறுதிகளின் "மேல்" வேலை செய்வதை நான் கவனிக்கிறேன். இந்த செயல்பாடுகள் தரமான வேறுபட்ட கருத்துகளை பிரதிநிதித்துவப்படுத்துவதில்லை. Async செயல்பாடுகள் வாக்குறுதிகளைப் பயன்படுத்தும் குறியீட்டிற்கு மாற்றாகக் கருதப்படுகின்றன.
ஒத்திசைவற்ற பாணியில் ஒத்திசைவற்ற குறியீட்டுடன் வேலையை ஒழுங்கமைப்பதை Async/Await சாத்தியமாக்குகிறது.
எனவே, வாக்குறுதிகளை அறிந்துகொள்வது Async/Await கொள்கைகளைப் புரிந்துகொள்வதை எளிதாக்குகிறது.
தொடரியல்
பொதுவாக இது இரண்டு முக்கிய வார்த்தைகளைக் கொண்டுள்ளது: ஒத்திசைவு மற்றும் காத்திரு. முதல் சொல் செயல்பாட்டை ஒத்திசைவற்றதாக மாற்றுகிறது. இத்தகைய செயல்பாடுகள் காத்திருப்பு பயன்படுத்த அனுமதிக்கின்றன. வேறு எந்த சந்தர்ப்பத்திலும், இந்த செயல்பாட்டைப் பயன்படுத்துவது பிழையை உருவாக்கும்.
// With function declaration
async function myFn() {
// await ...
}
// With arrow function
const myFn = async () => {
// await ...
}
function myFn() {
// await fn(); (Syntax Error since no async)
}
Async ஆனது செயல்பாடு அறிவிப்பின் ஆரம்பத்திலும், அம்புக்குறி செயல்பாட்டின் விஷயத்தில், “=” குறிக்கும் அடைப்புக்குறிக்கும் இடையில் செருகப்படும்.
இந்த செயல்பாடுகளை ஒரு பொருளில் முறைகளாக வைக்கலாம் அல்லது வகுப்பு அறிவிப்பில் பயன்படுத்தலாம்.
// As an object's method
const obj = {
async getName() {
return fetch('https://www.example.com');
}
}
// In a class
class Obj {
async getResource() {
return fetch('https://www.example.com');
}
}
NB! கிளாஸ் கன்ஸ்ட்ரக்டர்கள் மற்றும் பெறுபவர்கள்/செட்டர்கள் ஒத்திசைவற்றதாக இருக்க முடியாது என்பதை நினைவில் கொள்வது மதிப்பு.
சொற்பொருள் மற்றும் செயல்படுத்தல் விதிகள்
Async செயல்பாடுகள் அடிப்படையில் நிலையான JS செயல்பாடுகளைப் போலவே இருக்கும், ஆனால் விதிவிலக்குகள் உள்ளன.
எனவே, ஒத்திசைவு செயல்பாடுகள் எப்போதும் வாக்குறுதிகளை அளிக்கின்றன:
async function fn() {
return 'hello';
}
fn().then(console.log)
// hello
குறிப்பாக, fn ஹலோ என்ற சரத்தை வழங்குகிறது. சரி, இது ஒரு ஒத்திசைவற்ற செயல்பாடு என்பதால், சரம் மதிப்பு ஒரு கன்ஸ்ட்ரக்டரைப் பயன்படுத்தி ஒரு வாக்குறுதியில் மூடப்பட்டிருக்கும்.
Async இல்லாத மாற்று வடிவமைப்பு இதோ:
function fn() {
return Promise.resolve('hello');
}
fn().then(console.log);
// hello
இந்த வழக்கில், வாக்குறுதி "கைமுறையாக" திரும்பும். ஒரு ஒத்திசைவற்ற செயல்பாடு எப்போதும் ஒரு புதிய வாக்குறுதியில் மூடப்பட்டிருக்கும்.
திருப்பியளிக்கும் மதிப்பு ஒரு பழமையானதாக இருந்தால், ஒத்திசைவு செயல்பாடு ஒரு வாக்குறுதியில் அதைச் சுற்றி மதிப்பை வழங்குகிறது. திரும்பப்பெறும் மதிப்பு வாக்குறுதிப் பொருளாக இருந்தால், அதன் தீர்மானம் புதிய வாக்குறுதியில் வழங்கப்படும்.
const p = Promise.resolve('hello')
p instanceof Promise;
// true
Promise.resolve(p) === p;
// true
ஆனால் ஒத்திசைவற்ற செயல்பாட்டில் பிழை இருந்தால் என்ன நடக்கும்?
async function foo() {
throw Error('bar');
}
foo().catch(console.log);
இது செயலாக்கப்படாவிட்டால், foo() நிராகரிப்புடன் வாக்குறுதியை வழங்கும். இந்தச் சூழ்நிலையில், Promise.resolve என்பதற்குப் பதிலாகப் பிழையைக் கொண்ட Promise.reject வழங்கப்படும்.
Async செயல்பாடுகள் எப்பொழுதும் ஒரு வாக்குறுதியை வெளியிடுகின்றன, என்ன திரும்பப் பெறப்பட்டாலும்.
ஒவ்வொரு காத்திருப்பிலும் ஒத்திசைவற்ற செயல்பாடுகள் இடைநிறுத்தப்படும்.
காத்திருப்பு வெளிப்பாடுகளை பாதிக்கிறது. எனவே, வெளிப்பாடு ஒரு வாக்குறுதியாக இருந்தால், வாக்குறுதி நிறைவேற்றப்படும் வரை ஒத்திசைவு செயல்பாடு இடைநிறுத்தப்படும். வெளிப்பாடு வாக்குறுதியாக இல்லாவிட்டால், அது Promise.resolve வழியாக வாக்குறுதியாக மாற்றப்பட்டு பின்னர் முடிக்கப்படும்.
// utility function to cause delay
// and get random value
const delayAndGetRandom = (ms) => {
return new Promise(resolve => setTimeout(
() => {
const val = Math.trunc(Math.random() * 100);
resolve(val);
}, ms
));
};
async function fn() {
const a = await 9;
const b = await delayAndGetRandom(1000);
const c = await 5;
await delayAndGetRandom(1000);
return a + b * c;
}
// Execute fn
fn().then(console.log);
Fn செயல்பாடு எவ்வாறு செயல்படுகிறது என்பதற்கான விளக்கம் இங்கே உள்ளது.
அதை அழைத்த பிறகு, முதல் வரி const a = காத்திருப்பு 9 இலிருந்து மாற்றப்படுகிறது; in const a = காத்திருக்கவும் Promise.resolve(9);.
Await ஐப் பயன்படுத்திய பிறகு, a அதன் மதிப்பைப் பெறும் வரை செயல்பாடு செயல்படுத்தல் இடைநிறுத்தப்படும் (தற்போதைய சூழ்நிலையில் அது 9 ஆகும்).
delayAndGetRandom(1000) fn செயல்பாட்டின் செயல்பாட்டை அது தானாகவே முடிக்கும் வரை (1 வினாடிக்குப் பிறகு) இடைநிறுத்துகிறது. இது 1 வினாடிக்கு fn செயல்பாட்டை திறம்பட நிறுத்துகிறது.
delayAndGetRandom(1000) தீர்வு மூலம் ஒரு சீரற்ற மதிப்பை வழங்குகிறது, பின்னர் அது மாறி b க்கு ஒதுக்கப்படும்.
சரி, மாறி c இன் வழக்கு, மாறி a இல் உள்ளதைப் போன்றது. அதன் பிறகு, எல்லாம் ஒரு வினாடிக்கு நின்றுவிடும், ஆனால் இப்போது delayAndGetRandom(1000) எதுவும் திரும்பப் பெறவில்லை, ஏனெனில் அது தேவையில்லை.
இதன் விளைவாக, மதிப்புகள் a + b * c சூத்திரத்தைப் பயன்படுத்தி கணக்கிடப்படுகின்றன. முடிவு Promise.resolve ஐப் பயன்படுத்தி ஒரு வாக்குறுதியில் மூடப்பட்டு, செயல்பாட்டின் மூலம் திருப்பியளிக்கப்படுகிறது.
இந்த இடைநிறுத்தங்கள் ES6 இல் உள்ள ஜெனரேட்டர்களை நினைவூட்டுவதாக இருக்கலாம், ஆனால் அதில் ஏதோ இருக்கிறது உங்கள் காரணங்கள்.
சிக்கலைத் தீர்ப்பது
சரி, இப்போது மேலே குறிப்பிட்டுள்ள பிரச்சனைக்கான தீர்வைப் பார்ப்போம்.
queryDatabase, sendEmail, logTaskInFile மற்றும் பிற செயல்பாடுகளின் முடிவுகளுக்காகக் காத்திருக்க, finalMyTask செயல்பாடு Await ஐப் பயன்படுத்துகிறது. வாக்குறுதிகள் பயன்படுத்தப்பட்ட தீர்வுடன் இந்தத் தீர்வை ஒப்பிட்டுப் பார்த்தால், ஒற்றுமைகள் தெளிவாகத் தெரியும். இருப்பினும், Async/Await பதிப்பு அனைத்து தொடரியல் சிக்கல்களையும் பெரிதும் எளிதாக்குகிறது. இந்த வழக்கில், .then/.catch போன்ற கால்பேக்குகள் மற்றும் சங்கிலிகள் பெரிய அளவில் இல்லை.
எண்களின் வெளியீட்டில் ஒரு தீர்வு உள்ளது, இரண்டு விருப்பங்கள் உள்ளன.
const wait = (i, ms) => new Promise(resolve => setTimeout(() => resolve(i), ms));
// Implementation One (Using for-loop)
const printNumbers = () => new Promise((resolve) => {
let pr = Promise.resolve(0);
for (let i = 1; i <= 10; i += 1) {
pr = pr.then((val) => {
console.log(val);
return wait(i, Math.random() * 1000);
});
}
resolve(pr);
});
// Implementation Two (Using Recursion)
const printNumbersRecursive = () => {
return Promise.resolve(0).then(function processNextPromise(i) {
if (i === 10) {
return undefined;
}
return wait(i, Math.random() * 1000).then((val) => {
console.log(val);
return processNextPromise(i + 1);
});
});
};
மற்றும் இங்கே async செயல்பாடுகளை பயன்படுத்தி ஒரு தீர்வு உள்ளது.
async function printNumbersUsingAsync() {
for (let i = 0; i < 10; i++) {
await wait(i, Math.random() * 1000);
console.log(i);
}
}
செயலாக்கத்தில் பிழை
கையாளப்படாத பிழைகள் நிராகரிக்கப்பட்ட வாக்குறுதியில் மூடப்பட்டிருக்கும். இருப்பினும், ஒத்திசைவு செயல்பாடுகள் பிழைகளை ஒத்திசைக்க முயற்சி/பிடிப்பைப் பயன்படுத்தலாம்.
async function canRejectOrReturn() {
// wait one second
await new Promise(res => setTimeout(res, 1000));
// Reject with ~50% probability
if (Math.random() > 0.5) {
throw new Error('Sorry, number too big.')
}
return 'perfect number';
}
canRejectOrReturn() என்பது ஒரு ஒத்திசைவற்ற செயல்பாடாகும், இது வெற்றியடையும் ("சரியான எண்") அல்லது பிழையுடன் தோல்வியடையும் ("மன்னிக்கவும், எண் மிகவும் பெரியது").
மேலே உள்ள உதாரணம் canRejectOrReturn செயல்படுத்த வேண்டும் என்று எதிர்பார்க்கிறது என்பதால், அதன் சொந்த தோல்வி கேட்ச் பிளாக் செயல்படுத்தப்படும். இதன் விளைவாக, foo செயல்பாடு வரையறுக்கப்படாமல் (முயற்சித் தொகுதியில் எதுவும் திரும்பப் பெறாதபோது) அல்லது ஒரு பிழையுடன் முடிவடையும். இதன் விளைவாக, இந்த செயல்பாடு தோல்வியடையாது, ஏனெனில் முயற்சி/பிடிப்பு செயல்பாடு foo ஐயே கையாளும்.
எடுத்துக்காட்டில், canRejectOrReturn foo இலிருந்து திரும்பியது என்பதில் கவனம் செலுத்துவது மதிப்பு. ஃபூ இந்த விஷயத்தில் சரியான எண்ணுடன் முடிவடையும் அல்லது பிழையை (“மன்னிக்கவும், எண் மிகப் பெரியது”) வழங்கும். கேட்ச் பிளாக் ஒருபோதும் செயல்படுத்தப்படாது.
பிரச்சனை என்னவென்றால், canRejectOrReturn இலிருந்து நிறைவேற்றப்பட்ட வாக்குறுதியை foo திருப்பித் தருகிறது. எனவே foo க்கான தீர்வு canRejectOrReturn க்கு தீர்வாகும். இந்த வழக்கில், குறியீடு இரண்டு வரிகளை மட்டுமே கொண்டிருக்கும்:
மேலே உள்ள குறியீட்டில், சரியான எண் மற்றும் பிடிபட்ட பிழை ஆகிய இரண்டிலும் foo வெற்றிகரமாக வெளியேறும். இங்கே எந்த மறுப்பும் இருக்காது. ஆனால் foo canRejectOrReturn உடன் திரும்புவார், வரையறுக்கப்படாதது அல்ல. ரிட்டர்ன் காத்திருப்பு canRejectOrReturn() வரியை அகற்றுவதன் மூலம் இதை உறுதி செய்வோம்:
நீங்கள் பார்க்க முடியும் என, குறியீட்டில் காத்திருத்தல் அல்லது திரும்புதல் இல்லை. எனவே foo எப்போதும் 1 வினாடி தாமதமின்றி வரையறுக்கப்படாமல் வெளியேறும். ஆனால் வாக்குறுதி நிறைவேற்றப்படும். அது பிழை அல்லது நிராகரிப்பை எறிந்தால், UnhandledPromiseRejectionWarning என்று அழைக்கப்படும்.
கால்பேக்குகளில் ஒத்திசைவு செயல்பாடுகள்
Async செயல்பாடுகள் பெரும்பாலும் .map அல்லது .filter இல் கால்பேக்குகளாகப் பயன்படுத்தப்படுகின்றன. கிட்ஹப்பில் திறந்த களஞ்சியங்களின் எண்ணிக்கையை வழங்கும் fetchPublicReposCount(பயனர்பெயர்) செயல்பாடு ஒரு எடுத்துக்காட்டு. மூன்று பயனர்களின் அளவீடுகள் தேவை என்று வைத்துக்கொள்வோம். இந்த பணிக்கான குறியீடு இங்கே:
.map கால்பேக்கில் காத்திருப்பதில் கவனம் செலுத்துவது மதிப்பு. இங்கே கவுண்ட்ஸ் என்பது வாக்குறுதிகளின் வரிசையாகும், மேலும் .map என்பது ஒவ்வொரு குறிப்பிட்ட பயனருக்கும் ஒரு அநாமதேய அழைப்பாகும்.
காத்திருப்பின் அதிகப்படியான நிலையான பயன்பாடு
இந்த குறியீட்டை உதாரணமாக எடுத்துக் கொள்வோம்:
async function fetchAllCounts(users) {
const counts = [];
for (let i = 0; i < users.length; i++) {
const username = users[i];
const count = await fetchPublicReposCount(username);
counts.push(count);
}
return counts;
}
இங்கே ரெப்போ எண் எண்ணிக்கை மாறியில் வைக்கப்படுகிறது, பின்னர் இந்த எண் எண்ணிக்கை வரிசையில் சேர்க்கப்படும். குறியீட்டில் உள்ள சிக்கல் என்னவென்றால், முதல் பயனரின் தரவு சேவையகத்திலிருந்து வரும் வரை, அனைத்து அடுத்தடுத்த பயனர்களும் காத்திருப்பு பயன்முறையில் இருப்பார்கள். எனவே, ஒரு நேரத்தில் ஒரு பயனர் மட்டுமே செயலாக்கப்படுகிறார்.
எடுத்துக்காட்டாக, ஒரு பயனரைச் செயலாக்குவதற்கு சுமார் 300 எம்எஸ் எடுத்தால், எல்லா பயனர்களுக்கும் இது ஏற்கனவே ஒரு வினாடி ஆகும்; நேரியல் முறையில் செலவழித்த நேரம் பயனர்களின் எண்ணிக்கையைப் பொறுத்தது. ஆனால் ரெப்போவின் எண்ணிக்கையைப் பெறுவது ஒன்றுக்கொன்று சார்ந்திருக்காது என்பதால், செயல்முறைகளை இணையாகச் செய்யலாம். இதற்கு .map மற்றும் Promise.all உடன் வேலை செய்ய வேண்டும்:
Promise.all பல வாக்குறுதிகளை உள்ளீடாகப் பெறுகிறது மற்றும் வாக்குறுதியை வழங்குகிறது. பிந்தையது, வரிசையில் உள்ள அனைத்து வாக்குறுதிகளும் முடிந்த பிறகு அல்லது முதல் நிராகரிப்பில், நிறைவுற்றது. அவை அனைத்தும் ஒரே நேரத்தில் தொடங்காமல் இருக்கலாம் - ஒரே நேரத்தில் தொடங்குவதை உறுதிப்படுத்த, நீங்கள் p-map ஐப் பயன்படுத்தலாம்.
முடிவுக்கு
ஒத்திசைவு செயல்பாடுகள் வளர்ச்சிக்கு முக்கியத்துவம் பெறுகின்றன. சரி, ஒத்திசைவு செயல்பாடுகளின் தழுவல் பயன்பாட்டிற்கு, நீங்கள் பயன்படுத்த வேண்டும் ஒத்திசைவு இயக்கிகள். ஜாவாஸ்கிரிப்ட் டெவலப்பர் இதை நன்கு அறிந்திருக்க வேண்டும்.