Эгерде сиз жөн гана программалоону баштап жатсаңыз, анда сиз программаларды логиканын ырааттуу блокторунун жыйындысы катары ойлоп жатасыз, мында ар бир блок белгилүү бир нерсени жасайт жана анын жыйынтыгын кийинки блок иштете тургандай кылып өткөрүп берет жана башкалар үчүн. көпчүлүк бөлүгү сиз туура айтасыз, көпчүлүк программалар ырааттуу түрдө иштейт, бул модель бизге жазуу жана тейлөө үчүн жөнөкөй программаларды түзүүгө мүмкүндүк берет. Бирок бул ырааттуу модель иштебей турган же оптималдуу болбой турган конкреттүү колдонуу учурлары бар. Мисал катары, китеп окурмандын тиркемесин карап көрөлү. Бул колдонмо сөздүн бардык көрүнүштөрүн табуу, кыстармалар арасында чабыттоо жана ушул сыяктуу бир нече өркүндөтүлгөн өзгөчөлүктөргө ээ. Эми элестетиңиз, колдонуучу учурда узун китепти окуп жатат жана "The" сыяктуу жалпы сөздүн бардык көрүнүштөрүн издөөнү чечет. Тиркеме, адатта, ошол сөздүн бардык көрүнүштөрүн табуу жана индекстөө үчүн бир нече секунд талап кылынат. Издөө операциясы аткарылмайынча, ырааттуу программада колдонуучу тиркеме менен иштеше албайт (баракты өзгөртүү же текстти бөлүп көрсөтүү). Бул оптималдуу колдонуучу тажрыйбасы эмес экенин көрө аласыз деп үмүттөнөбүз!
Диаграмма китеп окугучтун тиркемесинин типтүү аткаруу агымын көрсөтөт. Эгерде колдонуучу узакка созулган операцияны баштаса (бул учурда чоң китепте ""тин бардык көрүнүштөрүн издөө), тиркеме ошол операциянын бардык мөөнөтүнө "тоңуп калат". Бул учурда, колдонуучу издөө операциясы аяктаганга чейин эч кандай натыйжасыз кийинки кыстарма баскычын басууну уланта берет жана бардык операциялар дароо күчүнө кирет, акыркы колдонуучуга артта калган тиркеме сезимин берет.
Сиз бул мисал чындыгында биз мурда киргизген ырааттуу моделге дал келбей турганын байкаган чыгарсыз. Себеби бул жердеги операциялар бири-биринен көз карандысыз. Кийинки кыстармага өтүү үчүн колдонуучуга "" дегендин канча жолу кайталанганын билиши керек эмес, андыктан операциялардын аткарылышынын тартиби чындыгында маанилүү эмес. Кийинки кыстармага өтүү үчүн издөө операциясынын бүтүшүн күтүүнүн кереги жок. Мурунку аткаруу агымынын мүмкүн болгон жакшыруусу ушул логикага негизделген: биз узак издөө операциясын фондо иштетип, бардык келген операцияларды уланта алабыз жана узак операция жасалгандан кийин, биз жөн гана колдонуучуга кабарлай алабыз. Аткаруу агымы төмөнкүдөй болот:
Бул аткаруу агымы менен, колдонуучу тажрыйбасы кыйла жакшырды. Эми колдонуучу узакка созулган операцияны баштап, тиркемени кадимкидей колдонууну уланта алат жана операция жасалгандан кийин кабар ала алат. Бул асинхрондук программалоонун негизи болуп саналат.
Javascript, башка тилдердин арасында, сиз ойлогон бардык асинхрондук жүрүм-турумга жетүү үчүн кеңири APIлерди камсыз кылуу менен асинхрондук программалоонун бул стилин колдойт. Күндүн аягында, Javascript табиятынан асинхрондук тил болушу керек. Мурунку мисалга кайрыла турган болсок, асинхрондук логика бардык колдонуучу менен өз ара аракеттенүү тиркемелеринин негизин түзөт жана Javascript негизинен браузерде колдонуу үчүн курулган, мында программалардын көбү колдонуучунун аракеттерине жооп кайтарууга багытталган.
Төмөнкүлөр сизге Асинхрондук Javascript боюнча кыскача жол көрсөтөт:
Кайра чалуулар
Кадимки программада сиз адатта бир катар функцияларды табасыз. Функцияны колдонуу үчүн, биз аны параметрлердин жыйындысы менен чакырабыз. Функциянын коду аткарылат жана натыйжаны кайтарат, адаттан тыш эч нерсе болбойт. Асинхрондук программалоо бул логиканы бир аз өзгөртөт. Китеп окугуч тиркемесинин мисалына кайрылсак, издөө операциясынын логикасын ишке ашыруу үчүн кадимки функцияны колдоно албайбыз, анткени операция белгисиз убакытты талап кылат. Кадимки функция негизинен операция жасалганга чейин кайтып келет жана бул биз күткөн жүрүм-турум эмес. Чечим издөө операциясы аткарылгандан кийин аткарыла турган башка функцияны көрсөтүү болуп саналат. Бул биздин колдонуу жагдайыбызды моделдейт, анткени биздин программа өз агымын кадимкидей уланта алат жана издөө операциясы аяктагандан кийин, көрсөтүлгөн функция издөө натыйжалары жөнүндө колдонуучуга кабарлоо үчүн аткарылат. Бул функцияны биз кайра чакыруу функциясы деп атайбыз:
// Search occurrences function
function searchOccurrences(word, callback) {
try {
// search operation logic, result is in result variable
//....
callback(null, word, result);
} catch (err) {
callback(err);
}
}
// Search occurrences callback function
function handleSearchOccurrencesResult(err, word, result) {
if (err) {
console.log(`Search operation for ${word} ended with an error`);
} else console.log(`Search results for ${word}: ${result}`);
return;
}
searchOccurrences("the", handleSearchOccurrencesResult);
Биринчиден, издөө операциясынын функциясын, searchOccurrences аныктайбыз. Бул издөө үчүн сөздү жана издөө операциясы аяктагандан кийин аткарыла турган функция болгон "кайра чалуу" экинчи параметрин талап кылат. Издөө операциясынын функциясы атайылап абстракттуу сакталган, биз анын эки мүмкүн болгон натыйжасына гана көңүл бурушубуз керек: биринчи учурда баары ийгиликтүү болгон жана бизде натыйжа өзгөрмөсүндө издөө натыйжасы бар. Бул учурда, биз жөн гана төмөнкү параметрлер менен кайра чалуу функциясын чакырышыбыз керек: биринчи параметр нөл дегенди билдирет, эч кандай ката болгон жок, экинчи параметр - изделген сөз, ал эми үчүнчү, балким, үч параметрдин эң маанилүү параметри., издөө иштеринин жыйынтыгы болуп саналат.
Экинчи учур - ката пайда болгон жерде, бул дагы издөө операциясынын аткарылышы жана биз кайра чалуу функциясын чакырышыбыз керек. Кандайдыр бир катаны токтотуу үчүн аракет кылуу жана кармоо блогун колдонобуз жана биз жөн гана catch блогунан ката объекти менен кайра чалуу функциясын чакырабыз.
Андан кийин кайра чалуу функциясын аныктадык, handleSearchOccurrences, биз анын логикасын абдан жөнөкөй сактадык. Бул жөн гана консолго билдирүү басып чыгаруу маселеси. Биз адегенде "err" параметрин текшерип, негизги функцияда кандайдыр бир ката болгон-болбогондугун текшеребиз. Мындай учурда биз жөн гана колдонуучуга издөө операциясы ката менен аяктаганын билдиребиз. Эгер эч кандай ката чыкпаса, издөө операциясынын жыйынтыгы менен билдирүүнү басып чыгарабыз.
Акыр-аягы, биз "the" деген сөз менен searchOccurrences функциясын чакырабыз. Функция эми негизги программаны бөгөттөбөстөн кадимкидей иштейт жана издөө аяктагандан кийин кайра чалуу аткарылат жана биз издөө натыйжасы же ката кабары менен жыйынтык кабарын алабыз.
Бул жерде айта кетүүчү нерсе, бизде негизги жана кайра чалуу функцияларынын ичиндеги натыйжа өзгөрмөсүнө гана мүмкүнчүлүк бар. Бул сыяктуу бир нерсе аракет кылсак:
let result;
function searchOccurrences(word, callback) {
try {
// search operation logic, result is in searchResult variable
//....
result = searchResult;
callback(null, word, result);
} catch (err) {
callback(err);
}
}
searchOccurrences("the", handleSearchOccurrencesResult);
console.log(result);
басып чыгаруунун натыйжасы аныкталбайт, анткени программалар searchOccurrences функциясынын аткарылышын күтүшпөйт. Ал негизги функциянын ичинде жыйынтык өзгөрмөсү дайындалганга чейин басып чыгаруу оператору болгон кийинки нускамага өтөт. Натыйжада, биз дайындалбаган жыйынтык өзгөрмөсүн басып чыгарабыз.
Ошентип, ушул логикага таянып, биз кайра чалуу функциясынын ичинде натыйжа өзгөрмөсүн колдонгон бардык кодду сакташыбыз керек. Бул азыр көйгөй эместей сезилиши мүмкүн, бирок ал тез эле чыныгы көйгөйгө айланып кетиши мүмкүн. Бизде ырааттуулукта иштеши керек болгон асинхрондук функциялардын тизмеги бар экенин элестетиңиз, типтүү кайра чалуу логикасында сиз төмөнкүдөй нерсени ишке ашырасыз:
functionA(function (err, resA) {
///......
functionB(resA, function (err, resB) {
///......
functionC(resB, function (err, resC) {
///......
functionD(resC, function (err, resD) {
///......
});
});
});
});
Ар бир кайра чалуунун ката параметри бар жана ар бир ката өзүнчө каралышы керек экенин унутпаңыз. Бул жогорудагы ансыз деле татаал кодду ого бетер татаал жана сактоого кыйын кылат. Буюрса, убадалар кайра чалуунун тозогу көйгөйүн чечүү үчүн бул жерде, биз муну кийинкиде чечебиз.
Убада
Убадалар кайра чалуулардын үстүнө курулат жана ушундай эле тартипте иштейт. Алар ES6 функцияларынын бир бөлүгү катары, мисалы, кайра чалуу тозогу сыяктуу кайра чалуулар менен бир нече көрүнүктүү маселелерди чечүү үчүн киргизилген. Убадалар ийгиликтүү аяктаганда (чечимде) жана каталар пайда болгондо (четке кагуу) өз функцияларын камсыз кылат. Төмөндө убадалар менен ишке ашырылган searchOccurrences мисалы көрсөтүлөт:
// Search occurrences function
function searchOccurrences(word) {
return new Promise((resolve, reject) => {
try {
// search operation logic, result is in result variable
//....
resolve(word, result);
} catch (err) {
reject(err);
}
});
}
searchOccurrences("the")
.then((word, result) => {
console.log(`Search results for ${word}: ${result}`);
})
.catch((err) => {
console.log(`Search operation ended with an error`);
});
Келгиле, биз колдонгон өзгөртүүлөрдү карап көрөлү:
SearchOccurrences функциясы убаданы кайтарат. Убаданын ичинде биз ошол эле логиканы сактайбыз: бизде ийгиликтүү аткарууну да, каталар менен аткарууну да тейлеген бир эле кайра чалуу функциясынын ордуна кайра чалууларыбызды билдирген чечүүчү жана четке кагуу функциясы бар. Убадалар эки натыйжаны бөлүп, негизги функцияны чакырганда таза синтаксисти камсыз кылат. Чечүү функциясы "андан кийин" ачкыч сөзүн колдонуу менен негизги функцияга "байланган". Бул жерде биз жөн гана чечүү функциясынын эки параметрин көрсөтүп, издөө натыйжасын басып чыгарабыз. Окшош нерсе четке кагуу функциясына да тиешелүү, аны "кармап алуу" ачкыч сөзү менен байлап койсо болот. Коддун окулушу жана тазалыгы боюнча убадалардын артыкчылыктарын баалай аласыз деп үмүттөнөбүз. Эгер сиз дагы эле аны талкуулап жатсаңыз, асинхрондук функцияларды биринин артынан бири иштетүү үчүн чынжырлап, кайра чалуу тозогу көйгөйүн кантип чече аларыбызды карап көрүңүз:
searchOccurrences("the")
.then(searchOccurrences("asynchronous"))
.then(searchOccurrences("javascript"))
.then(searchOccurrences("guide"))
.catch((err) => {
console.log(`Search operation ended with an error`);
});
Асинхрондоштуруу/Күтүү
Async/Await биздин Javascript'теги асинхрондук курал курубузга эң акыркы кошумча болуп саналат. ES8 менен киргизилген, алар асинхрондук операциянын аткарылышын "күтүү" аркылуу асинхрондук функциялардын үстүнө абстракциянын жаңы катмарын камсыз кылат. Программанын агымы ошол нускама боюнча асинхрондук операциядан натыйжа кайтарылганга чейин блоктолот жана андан кийин программа кийинки нускама менен уланат. Эгер сиз синхрондуу аткаруу агымы жөнүндө ойлонуп жатсаңыз, анда сиз туура. Биз толук чөйрөгө келдик! Синхрондуу программалоонун жөнөкөйлүгүн асинхрондуу дүйнөгө алып келүү аракети Асинхрондо/күтүүдө. Бул программанын аткарылышында жана кодунда гана кабылданарын эстен чыгарбаңыз. Капоттун астында баары ошол эле бойдон калат, Async/wait дагы эле убадаларды колдонуп жатышат жана кайра чалуулар алардын курулуш материалы болуп саналат.
Келгиле, биздин мисалды карап чыгалы жана аны Async/await аркылуу ишке ашыралы:
async function searchOccurrences(word) {
try {
// search operation logic, result is in result variable
//....
return result;
} catch (err) {
console.log(`Search operation for ${word} ended with an error`);
}
}
const word = "the";
const result = await searchOccurrences(word, handleSearchOccurrencesResult);
console.log(`Search results for ${word}: ${result}`);
Биздин код анча деле өзгөргөн жок, бул жерде байкай турган маанилүү нерсе - searchOccurrences функциясынын декларациясынын алдындагы “async” ачкыч сөзү. Бул функция асинхрондуу экенин көрсөтүп турат. Ошондой эле, searchOccurrences функциясын чакырганда "күтүү" ачкыч сөзүнө көңүл буруңуз. Бул программа кийинки инструкцияга өткөнгө чейин натыйжа кайтарылганга чейин функциянын аткарылышын күтүүнү буйруйт, башкача айтканда, натыйжа өзгөрмөсү ар дайым SearchOccurrences функциясынын кайтарылган маанисин кармап турат, бирок убадасын эмес. функциясы, бул мааниде, Async/Awaitтин Убадалар катары күтүү абалы жок. Аткаруу аяктагандан кийин, биз басып чыгаруу операторуна өтөбүз жана бул жолу натыйжа иш жүзүндө издөө операциясынын натыйжасын камтыйт. Күтүлгөндөй, жаңы код синхрондуу болгон сыяктуу эле жүрүм-турумга ээ.
Эске алчу дагы бир кичинекей нерсе, бизде кайра чалуу функциялары жок болгондуктан, ошол эле функциянын ичиндеги searchOccurrences катасын чечишибиз керек, анткени биз катаны кайра чалуу функциясына жайылтып, аны ошол жерде иштете албайбыз. Бул жерде биз мисал үчүн ката болгон учурда ката билдирүүсүн басып чыгарып жатабыз.
Киришүү
Бул макалада биз Javascriptте асинхрондук логиканы ишке ашыруу үчүн колдонулган ар кандай ыкмаларды карап чыктык. Биз программалоонун кадимки синхрондук стилинен асинхрондук моделге эмне үчүн өтүшүбүз керек экендигинин конкреттүү мисалын изилдөө менен баштадык. Андан кийин биз асинхрондук Javascriptтин негизги курулуш блоктору болгон кайра чалууларга өттүк. Кайра чалуулардын чектөөлөрү бизди бул чектөөлөрдү жеңүү үчүн жылдар бою кошулган ар кандай альтернативаларга алып келди, негизинен убадалар жана Async/ күтүү. Асинхрондук логиканы интернеттин каалаган жеринен тапса болот, мейли тышкы API чакырып жатасызбы, маалымат базасына суроо-талапты баштагансызбы, локалдык файл тутумуна жазып жатасызбы, жада калса кирүү формасында колдонуучунун киргизүүсүн күтүп жатасызбы. Эми сиз таза жана туруктуу Асинхрондук Javascript жазуу менен бул маселелерди чечүүгө көбүрөөк ишенесиз деп үмүттөнөбүз!
Эгер сизге бул макала жакса, CLA блогун карап көрүңүз, анда биз технологияга кантип кирүү боюнча ар кандай темаларды талкуулайбыз. Ошондой эле, youtube каналыбызды мурунку акысыз семинарларыбызды текшерип, социалдык медиада бизге көз салыңыз. -labs-academy/) ошондуктан алдыдагыларды өткөрүп жибербеңиз!