Asinhronā JavaScript rokasgrāmata iesācējiem

javascript
promises
AsyncAwait
Asinhronā JavaScript rokasgrāmata iesācējiem cover image

Ja jūs tikai sākat programmēt, iespējams, jūs domājat par programmām kā secīgu loģikas bloku kopu, kur katrs bloks veic noteiktu darbību un nodod savu rezultātu, lai varētu palaist nākamo bloku un tā tālāk, un lielākoties jums ir taisnība, lielākā daļa programmu darbojas secīgi, šis modelis ļauj mums izveidot programmas, kuras ir vienkārši rakstīt un uzturēt. Tomēr ir īpaši lietošanas gadījumi, kad šis secīgais modelis nedarbosies vai nebūtu optimāls. Kā piemēru apsveriet grāmatu lasītāja lietojumprogrammu. Šai lietojumprogrammai ir dažas uzlabotas funkcijas, piemēram, visu vārda gadījumu atrašana, navigācija starp grāmatzīmēm un tamlīdzīgi. Tagad iedomājieties, ka lietotājs pašlaik lasa garu grāmatu un nolemj meklēt visus sastopamos vārdus, piemēram, “The”. Lietojumprogrammai parasti būs nepieciešamas dažas sekundes, lai atrastu un indeksētu visus šī vārda gadījumus. Secīgā programmā lietotājs nevar mijiedarboties ar lietojumprogrammu (mainīt lapu vai izcelt tekstu), kamēr nav izpildīta meklēšanas darbība. Cerams, ka jūs redzēsit, ka tā nav optimāla lietotāja pieredze!

1

Diagramma ilustrē tipisku grāmatu lasītāja lietojumprogrammas izpildes plūsmu. Ja lietotājs uzsāk ilgstošu darbību (šajā gadījumā meklē visus “the” gadījumus lielā grāmatā), lietojumprogramma “sasalst” uz visu šīs darbības laiku. Šādā gadījumā lietotājs turpinās klikšķināt uz nākamās grāmatzīmes pogas bez rezultāta, līdz meklēšanas darbība būs pabeigta, un visas darbības stāsies spēkā uzreiz, radot galalietotājam atpaliekošas lietojumprogrammas sajūtu.

Jūs, iespējams, pamanījāt, ka šis piemērs īsti neatbilst iepriekš ieviestajam secīgajam modelim. Tas ir tāpēc, ka darbības šeit ir neatkarīgas viena no otras. Lai pārietu uz nākamo grāmatzīmi, lietotājam nav jāzina par "the" gadījumu skaitu, tāpēc darbību izpildes secība nav īsti svarīga. Mums nav jāgaida meklēšanas darbības beigas, lai mēs varētu pāriet uz nākamo grāmatzīmi. Iespējamais iepriekšējās izpildes plūsmas uzlabojums ir balstīts uz šo loģiku: mēs varam palaist garo meklēšanas darbību fonā, turpināt visas ienākošās darbības, un, kad garā darbība ir pabeigta, mēs varam vienkārši informēt lietotāju. Izpildes plūsma kļūst šāda:

2

Izmantojot šo izpildes plūsmu, lietotāja pieredze ir ievērojami uzlabota. Tagad lietotājs var uzsākt ilgstošu darbību, turpināt lietot lietojumprogrammu kā parasti un saņemt paziņojumu, kad darbība ir pabeigta. Tas ir asinhronās programmēšanas pamats.

Javascript, cita starpā, atbalsta šo asinhronās programmēšanas stilu, nodrošinot plašas API, lai sasniegtu gandrīz jebkuru asinhrono darbību, kādu vien varat iedomāties. Galu galā Javascript pēc savas būtības vajadzētu būt asinhronai valodai. Ja mēs atsaucamies uz iepriekšējo piemēru, asinhronā loģika ir visu lietotāju mijiedarbības lietojumprogrammu pamatā, un Javascript galvenokārt tika izstrādāts, lai to izmantotu pārlūkprogrammā, kurā lielākā daļa programmu ir paredzētas, lai reaģētu uz lietotāja darbībām.

Tālāk sniegta īsa rokasgrāmata par asinhrono Javascript:

Atzvani

Parastajā programmā jūs parasti atradīsit vairākas funkcijas. Lai izmantotu funkciju, mēs to saucam ar parametru kopu. Funkcijas kods tiks izpildīts un atgriezīs rezultātu, nekas neparasts. Asinhronā programmēšana nedaudz maina šo loģiku. Atgriežoties pie grāmatu lasītāja lietojumprogrammas piemēra, mēs nevaram izmantot parasto funkciju, lai ieviestu meklēšanas darbības loģiku, jo darbība aizņem nezināmu laiku. Parasta funkcija būtībā atgriezīsies pirms operācijas pabeigšanas, un tā nav tā, kā mēs sagaidām. Risinājums ir norādīt citu funkciju, kas tiks izpildīta pēc meklēšanas darbības. Tas modelē mūsu lietošanas gadījumu, jo mūsu programma var turpināt savu plūsmu kā parasti, un pēc meklēšanas darbības pabeigšanas tiks izpildīta norādītā funkcija, lai informētu lietotāju par meklēšanas rezultātiem. Šo funkciju mēs saucam par atzvanīšanas funkciju:

// 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);

Pirmkārt, mēs definējam meklēšanas darbības funkciju searchOccurrences. Nepieciešams meklētais vārds un otrs parametrs “atzvanīšana”, kas būs funkcija, kas jāizpilda pēc meklēšanas darbības. Meklēšanas operācijas funkcija tika apzināti saglabāta abstrakta, mums ir jākoncentrējas tikai uz tās diviem iespējamiem rezultātiem: pirmajā gadījumā viss noritēja veiksmīgi, un mums ir meklēšanas rezultāts rezultātu mainīgajā. Šajā gadījumā mums vienkārši jāizsauc atzvanīšanas funkcija ar šādiem parametriem: pirmais parametrs ir nulle, kas nozīmē, ka nav notikusi kļūda, otrais parametrs ir meklētais vārds un trešais un, iespējams, vissvarīgākais parametrs no trim., ir meklēšanas darbības rezultāts.

Otrais gadījums ir kļūda, šis ir arī gadījums, kad tiek veikta meklēšanas operācija un mums ir jāizsauc atzvanīšanas funkcija. Mēs izmantojam mēģinājuma un uztveršanas bloku, lai pārtvertu jebkuru kļūdu, un mēs vienkārši izsaucam atzvanīšanas funkciju ar kļūdas objektu no uztveršanas bloka.

Pēc tam mēs definējām atzvanīšanas funkciju handleSearchOccurrences, saglabājām tās loģiku diezgan vienkāršu. Tas ir tikai jautājums par ziņojuma drukāšanu konsolei. Vispirms mēs pārbaudām parametru “err”, lai redzētu, vai galvenajā funkcijā nav radusies kļūda. Tādā gadījumā mēs vienkārši informējam lietotāju, ka meklēšanas darbība beidzās ar kļūdu. Ja kļūdas netika parādītas, mēs izdrukājam ziņojumu ar meklēšanas darbības rezultātu.

Visbeidzot, funkciju searchOccurrences mēs saucam ar vārdu “the”. Funkcija tagad darbosies normāli, nebloķējot galveno programmu, un pēc meklēšanas pabeigšanas tiks izpildīts atzvans, un mēs saņemsim rezultāta ziņojumu ar meklēšanas rezultātu vai kļūdas ziņojumu.

Šeit ir svarīgi pieminēt, ka mums ir piekļuve tikai rezultāta mainīgajam galvenajā un atzvanīšanas funkcijās. Ja mēģinām kaut ko līdzīgu šim:

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);

drukāšanas rezultāts nebūtu definēts, jo programmas negaida, līdz tiks izpildīta funkcija searchOccurrences. Tas pāriet uz nākamo instrukciju, kas ir drukas paziņojums, pirms galvenās funkcijas ietvaros tiek piešķirts rezultāta mainīgais. Rezultātā mēs izdrukāsim nepiešķirto rezultāta mainīgo.

Tāpēc, pamatojoties uz šo loģiku, mums viss kods, kas izmanto rezultāta mainīgo, ir jāsaglabā atzvanīšanas funkcijā. Tagad tā var nešķist problēma, taču tā var ātri pāraugt reālā problēmā. Iedomājieties gadījumu, kad mums ir asinhronu funkciju ķēde, kurām jādarbojas secīgi. Tipiskā atzvanīšanas loģikā jūs ieviestu kaut ko līdzīgu:

functionA(function (err, resA) {
  ///......
  functionB(resA, function (err, resB) {
    ///......
    functionC(resB, function (err, resC) {
      ///......
      functionD(resC, function (err, resD) {
        ///......
      });
    });
  });
});

Ņemiet vērā, ka katram atzvanīšanai ir kļūdas parametrs un katra kļūda ir jārisina atsevišķi. Tas jau tā sarežģīto kodu padara vēl sarežģītāku un grūtāk uzturējamu. Cerams, Promises ir šeit, lai atrisinātu atzvanīšanas elles problēmu. Mēs to apskatīsim tālāk.

Solījumi

Solījumi ir balstīti uz atzvanīšanu un darbojas līdzīgi. Tie tika ieviesti kā daļa no ES6 funkcijām, lai atrisinātu dažas acīmredzamas problēmas ar atzvanīšanu, piemēram, atzvanīšanas elle. Solījumi nodrošina savas funkcijas, kas darbojas pēc veiksmīgas pabeigšanas (atrisināšana) un kļūdu gadījumā (noraidīšana). Tālāk ir parādīts piemērs searchOccurrences, kas ieviests ar solījumiem:

// 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`);
  });

Apskatīsim mūsu piemērotās izmaiņas:

Funkcija searchOccurrences atgriež solījumu. Solījuma ietvaros mēs saglabājam to pašu loģiku: mums ir divas atrisināšanas un noraidīšanas funkcijas, kas atspoguļo mūsu atzvanīšanu, nevis vienu atzvanīšanas funkciju, kas apstrādā gan veiksmīgu izpildi, gan izpildi ar kļūdām. Solījumi atdala abus rezultātus un nodrošina tīru sintaksi, izsaucot galveno funkciju. Atrisināšanas funkcija ir “piesaistīta” galvenajai funkcijai, izmantojot atslēgvārdu “tad”. Šeit mēs vienkārši norādām divus atrisināšanas funkcijas parametrus un izdrukājam meklēšanas rezultātu. Līdzīga lieta attiecas uz noraidīšanas funkciju, to var piesaistīt, izmantojot atslēgvārdu “catch”. Cerams, ka jūs varat novērtēt solījumu sniegtās priekšrocības koda lasāmības un tīrības ziņā. Ja jūs joprojām par to diskutējat, pārbaudiet, kā mēs varam atrisināt atzvanīšanas elles problēmu, savienojot asinhronās funkcijas, lai tās darbotos vienu pēc otras:

searchOccurrences("the")
  .then(searchOccurrences("asynchronous"))
  .then(searchOccurrences("javascript"))
  .then(searchOccurrences("guide"))
  .catch((err) => {
    console.log(`Search operation ended with an error`);
  });

Asinhronizēt/gaida

Async/Await ir jaunākais papildinājums mūsu Javascript asinhronajai rīkjoslai. Ieviestas ar ES8, tie nodrošina jaunu abstrakcijas slāni papildus asinhronajām funkcijām, vienkārši "gaidot" asinhronās darbības izpildi. Programmas plūsma bloķē šo instrukciju, līdz tiek atgriezts rezultāts no asinhronās darbības, un tad programma turpinās ar nākamo instrukciju. Ja domājat par sinhrono izpildes plūsmu, jums ir taisnība. Esam tikuši pie pilna apļa! Async/wait mēģinājumi ieviest sinhronās programmēšanas vienkāršību asinhronajā pasaulē. Lūdzu, ņemiet vērā, ka tas tiek uztverts tikai programmas izpildē un kodā. Zem pārsega viss paliek nemainīgs, Async/await joprojām izmanto solījumus, un atzvani ir viņu pamatelementi.

Pārskatīsim mūsu piemēru un ieviesīsim to, izmantojot 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}`);

Mūsu kods daudz nemainījās, šeit ir svarīgi pamanīt atslēgvārdu “async” pirms SearchCurrences funkcijas deklarācijas. Tas norāda, ka funkcija ir asinhrona. Izsaucot funkciju SearchCurrences, ievērojiet arī atslēgvārdu “gaidīt”. Tas liks programmai gaidīt funkcijas izpildi, līdz tiek atgriezts rezultāts, pirms programma var pāriet uz nākamo instrukciju, citiem vārdiem sakot, rezultāta mainīgajam vienmēr būs atgrieztā funkcija searchOccurrences, nevis solījums funkcijai šajā ziņā Async/Await nav gaidīšanas statusa kā solījumi. Kad izpilde ir pabeigta, mēs pārietam uz drukas paziņojumu, un šoreiz rezultāts faktiski satur meklēšanas darbības rezultātu. Kā gaidīts, jaunajam kodam ir tāda pati darbība, it kā tas būtu sinhrons.

Vēl viena neliela lieta, kas jāpatur prātā, ir tāda, ka, tā kā mums vairs nav atzvanīšanas funkciju, mums ir jāapstrādā kļūda searchOccurrences tajā pašā funkcijā, jo mēs nevaram vienkārši izplatīt kļūdu uz atzvanīšanas funkciju un apstrādāt to tur. Šeit mēs vienkārši izdrukām kļūdas ziņojumu kļūdas gadījumā piemēra labad.

Noslēgums

Šajā rakstā mēs apskatījām dažādas pieejas, kas tiek izmantotas asinhronās loģikas ieviešanai Javascript. Mēs sākām, izpētot konkrētu piemēru, kāpēc mums vajadzētu pāriet no parastā sinhronā programmēšanas stila uz asinhrono modeli. Pēc tam mēs pārgājām uz atzvanīšanu, kas ir galvenie asinhronā Javascript elementi. Atzvanīšanas ierobežojumi noveda mūs pie dažādām alternatīvām, kas tika pievienotas gadu gaitā, lai pārvarētu šos ierobežojumus, galvenokārt solījumus un Async/wait. Asinhrono loģiku var atrast jebkur tīmeklī, neatkarīgi no tā, vai izsaucat ārēju API, iniciējat datu bāzes vaicājumu, rakstāt lokālajā failu sistēmā vai pat gaidāt lietotāja ievadi pieteikšanās veidlapā. Cerams, ka tagad jūtaties pārliecinātāks, lai risinātu šīs problēmas, rakstot tīru un uzturējamu asinhrono Javascript!

Ja jums patīk šis raksts, lūdzu, skatiet CLA emuāru, kurā mēs apspriežam dažādas tēmas par to, kā apgūt tehnoloģiju. Apskatiet arī mūsu youtube kanālu, lai skatītu mūsu iepriekšējos bezmaksas seminārus, un sekojiet mums sociālajos medijos, lai jūs nepalaistu garām gaidāmos!


Career Services background pattern

Karjeras pakalpojumi

Contact Section background image

Sazināsimies

Code Labs Academy © 2024 Visas tiesības paturētas.