Asinchroninio JavaScript vadovas pradedantiesiems

javascript
promises
AsyncAwait
Asinchroninio JavaScript vadovas pradedantiesiems cover image

Jei tik pradedate programuoti, tikėtina, kad galvojate apie programas kaip apie nuoseklių logikos blokų rinkinį, kur kiekvienas blokas atlieka tam tikrą veiksmą ir perduoda rezultatą, kad būtų galima paleisti kitą bloką ir pan. didžioji dalis jūs teisus, dauguma programų veikia nuosekliai, šis modelis leidžia mums kurti programas, kurias paprasta rašyti ir prižiūrėti. Tačiau yra konkrečių naudojimo atvejų, kai šis nuoseklus modelis neveiks arba nebūtų optimalus. Kaip pavyzdį apsvarstykite knygų skaitymo programą. Ši programa turi keletą išplėstinių funkcijų, tokių kaip visų žodžio atvejų paieška, naršymas tarp žymių ir panašiai. Dabar įsivaizduokite, kad vartotojas šiuo metu skaito ilgą knygą ir nusprendžia ieškoti visų įprasto žodžio, pvz., „The“, atvejų. Paprastai programai prireiks kelių sekundžių, kad surastų ir suindeksuotų visus to žodžio atvejus. Nuoseklioje programoje vartotojas negali sąveikauti su programa (keisti puslapio ar paryškinti teksto), kol nebus atlikta paieškos operacija. Tikimės, kad pamatysite, kad tai nėra optimali vartotojo patirtis!

1

Diagrama iliustruoja tipišką knygų skaitymo programos vykdymo eigą. Jei vartotojas inicijuoja ilgai vykdomą operaciją (šiuo atveju ieško visų „the“ atvejų didelėje knygoje), programa „užstringa“ visam tos operacijos laikui. Tokiu atveju vartotojas ir toliau spustelės kitą žymės mygtuką be rezultato, kol paieškos operacija bus baigta, o visos operacijos įsigalios iš karto, todėl galutiniam vartotojui atrodo, kad programa vėluoja.

Galbūt pastebėjote, kad šis pavyzdys iš tikrųjų neatitinka nuoseklaus modelio, kurį pristatėme anksčiau. Taip yra todėl, kad operacijos čia yra nepriklausomos viena nuo kitos. Vartotojui nereikia žinoti apie „the“ atvejų skaičių, kad galėtų pereiti prie kitos žymės, todėl operacijų vykdymo tvarka nėra labai svarbi. Mums nereikia laukti paieškos operacijos pabaigos, kad galėtume pereiti prie kitos žymės. Galimas ankstesnio vykdymo srauto patobulinimas pagrįstas šia logika: galime paleisti ilgą paieškos operaciją fone, tęsti bet kokias gaunamas operacijas, o atlikę ilgą operaciją, galime tiesiog informuoti vartotoją. Vykdymo eiga tampa tokia:

2

Naudojant šį vykdymo srautą, vartotojo patirtis žymiai pagerėjo. Dabar vartotojas gali inicijuoti ilgai vykdomą operaciją, pradėti naudoti programą įprastai ir gauti pranešimą, kai operacija bus atlikta. Tai yra asinchroninio programavimo pagrindas.

„Javascript“, be kitų kalbų, palaiko šį asinchroninio programavimo stilių, teikdama plačias API, kad pasiektų beveik bet kokį asinchroninį elgesį. Galų gale, „Javascript“ iš esmės turėtų būti asinchroninė kalba. Jei remsimės ankstesniu pavyzdžiu, asinchroninė logika yra visų vartotojų sąveikos programų pagrindas, o Javascript pirmiausia buvo sukurtas naudoti naršyklėje, kurioje dauguma programų yra skirtos reaguoti į vartotojo veiksmus.

Toliau pateikiamas trumpas asinchroninio Javascript vadovas:

Atgaliniai skambučiai

Įprastoje programoje paprastai rasite daugybę funkcijų. Norėdami naudoti funkciją, vadiname ją parametrų rinkiniu. Funkcijos kodas bus vykdomas ir pateiks rezultatą, nieko neįprasto. Asinchroninis programavimas šiek tiek pakeičia šią logiką. Grįžtant prie knygų skaitymo programos pavyzdžio, negalime naudoti įprastos funkcijos paieškos operacijos logikai įgyvendinti, nes operacija trunka nežinomą laiką. Įprasta funkcija iš esmės grįš prieš atliekant operaciją, o tai nėra tokia, kokios tikimės. Sprendimas yra nurodyti kitą funkciją, kuri bus vykdoma atlikus paieškos operaciją. Tai modeliuoja mūsų naudojimo atvejį, nes mūsų programa gali tęsti savo eigą įprastai, o kai paieškos operacija bus baigta, nurodyta funkcija bus vykdoma, kad praneštų vartotojui apie paieškos rezultatus. Šią funkciją vadiname atgalinio ryšio funkcija:

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

Pirmiausia apibrėžiame paieškos operacijos funkciją, searchOccurrences. Tam reikia žodžio ieškoti ir antrojo parametro „atskambinimo“, kuris bus funkcija, kuri bus vykdoma atlikus paieškos operaciją. Paieškos operacijos funkcija buvo sąmoningai laikoma abstrakčia, tereikia sutelkti dėmesį į du galimus jos rezultatus: pirmuoju atveju viskas pavyko sėkmingai, o paieškos rezultatą turime rezultatų kintamajame. Šiuo atveju tereikia iškviesti atgalinio ryšio funkciją su šiais parametrais: pirmasis parametras yra nulis, reiškiantis, kad neįvyko klaida, antrasis parametras yra ieškomas žodis ir trečiasis ir galbūt svarbiausias parametras iš trijų., yra paieškos operacijos rezultatas.

Antrasis atvejis, kai įvyksta klaida, tai taip pat yra atvejis, kai atliekama paieškos operacija ir mes turime iškviesti atgalinio ryšio funkciją. Mes naudojame bandymo ir gaudymo bloką, kad perimtume bet kokią klaidą, ir tiesiog iškviečiame atgalinio ryšio funkciją su klaidos objektu iš gaudymo bloko.

Tada apibrėžėme atgalinio skambučio funkciją handSearchOccurrences, išlaikėme jos logiką gana paprastą. Tereikia atspausdinti pranešimą į konsolę. Pirmiausia patikriname parametrą „err“, kad pamatytume, ar pagrindinėje funkcijoje įvyko klaida. Tokiu atveju mes tiesiog informuojame vartotoją, kad paieškos operacija baigėsi klaida. Jei klaidų nebuvo, išspausdiname pranešimą su paieškos operacijos rezultatu.

Galiausiai funkciją searchOccurrences vadiname žodžiu „the“. Funkcija dabar veiks normaliai, neblokuodama pagrindinės programos, o atlikus paiešką, bus atliktas atgalinis skambutis ir mes gausime rezultato pranešimą su paieškos rezultatu arba klaidos pranešimu.

Čia svarbu paminėti, kad mes turime prieigą tik prie rezultato kintamojo pagrindinėje ir atgalinio ryšio funkcijose. Jei bandysime kažką panašaus:

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

spausdinimo rezultatas būtų neapibrėžtas, nes programos nelaukia, kol bus vykdoma funkcija searchOccurrences. Jis pereina prie kitos instrukcijos, kuri yra spausdinimo sakinys, prieš priskiriant rezultato kintamąjį pagrindinėje funkcijoje. Dėl to mes išspausdinsime nepriskirtą rezultato kintamąjį.

Taigi, remiantis šia logika, visą kodą, kuris naudoja rezultato kintamąjį, turėtume laikyti atgalinio skambinimo funkcijoje. Dabar tai gali neatrodyti problema, bet greitai gali peraugti į tikrą problemą. Įsivaizduokite atvejį, kai turime asinchroninių funkcijų grandinę, kurios turi būti vykdomos iš eilės. Įprastoje atgalinio skambučio logikoje įgyvendintumėte kažką panašaus į tai:

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

Atminkite, kad kiekvienas atgalinis skambutis turi klaidos parametrą ir kiekviena klaida turi būti tvarkoma atskirai. Dėl to aukščiau pateiktas ir taip sudėtingas kodas tampa dar sudėtingesnis ir sunkiai prižiūrimas. Tikimės, kad pažadai yra čia, kad išspręstų atšaukimo pragaro problemą. Mes tai aptarsime toliau.

Pažadai

Pažadai remiasi atgaliniais skambučiais ir veikia panašiai. Jie buvo pristatyti kaip ES6 funkcijų dalis, siekiant išspręsti kelias akivaizdžias problemas, susijusias su atgaliniais skambučiais, pvz., atgalinio skambučio pragarą. Pažadai suteikia savo funkcijas, kurios veikia sėkmingai užbaigus (išspręsti) ir kai atsiranda klaidų (atmesti). Toliau pateikiamas „SearchCurrences“ pavyzdys, įgyvendintas su pažadais:

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

Peržiūrėkime pritaikytus pakeitimus:

Funkcija searchOccurrences grąžina pažadą. Pažaduose laikomės tos pačios logikos: turime dvi sprendimo ir atmetimo funkcijas, kurios atspindi mūsų atgalinius skambučius, o ne vieną atgalinio skambinimo funkciją, kuri apdoroja ir sėkmingą vykdymą, ir vykdymą su klaidomis. Pažadai atskiria du rezultatus ir suteikia aiškią sintaksę iškviečiant pagrindinę funkciją. Išspręsimo funkcija „prijungiama“ prie pagrindinės funkcijos naudojant raktinį žodį „tada“. Čia mes tiesiog nurodome du sprendimo funkcijos parametrus ir išspausdiname paieškos rezultatą. Panašus dalykas galioja ir atmetimo funkcijai, ją galima užkabinti naudojant raktinį žodį „pagauti“. Tikimės, kad galėsite įvertinti pažadų pranašumus, susijusius su kodo skaitomumu ir švara. Jei vis dar diskutuojate, patikrinkite, kaip galime išspręsti atgalinio ryšio pragaro problemą sujungdami asinchronines funkcijas, kad jos veiktų viena po kitos:

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

Asinchronizuoti / laukti

„Async/Await“ yra naujausias mūsų asinchroninio „Javascript“ įrankių juostos papildymas. Įdiegti su ES8, jie suteikia naują abstrakcijos sluoksnį be asinchroninių funkcijų, tiesiog „laukdami“, kol bus atlikta asinchroninė operacija. Programos eiga blokuoja tą instrukciją, kol asinchroninės operacijos rezultatas bus grąžintas, o tada programa tęs kitą komandą. Jei galvojate apie sinchroninį vykdymo srautą, esate teisus. Apėjome pilną ratą! Asinchroninis / laukimas bando perkelti sinchroninio programavimo paprastumą į asinchroninį pasaulį. Atminkite, kad tai suvokiama tik programos vykdyme ir kode. Po gaubtu viskas lieka taip pat, Async/await vis dar naudoja pažadus, o atgaliniai skambučiai yra jų sudedamoji dalis.

Peržiūrėkime savo pavyzdį ir įgyvendinkime jį naudodami 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ūsų kodas beveik nepasikeitė, čia svarbu atkreipti dėmesį į raktinį žodį „async“ prieš „SearchCurrences“ funkcijos deklaraciją. Tai rodo, kad funkcija yra asinchroninė. Taip pat atkreipkite dėmesį į raktinį žodį „laukti“, kai skambinate funkcija „SearchOccurrences“. Tai nurodys programai palaukti, kol bus įvykdyta funkcija, kol bus grąžintas rezultatas, kol programa galės pereiti prie kitos komandos, kitaip tariant, rezultato kintamasis visada turės grąžintą funkcijos searchOccurrences reikšmę, o ne pažadą Šia prasme funkcija Async/Await neturi laukiančios būsenos kaip pažadai. Kai vykdymas baigtas, pereiname prie spausdinimo teiginio ir šį kartą rezultate iš tikrųjų yra paieškos operacijos rezultatas. Kaip ir tikėtasi, naujasis kodas veikia taip pat, tarsi jis būtų sinchroninis.

Kitas nedidelis dalykas, kurį reikia nepamiršti, yra tai, kad nebeturime atgalinio skambinimo funkcijų, todėl turime tvarkyti paieškos įvykių klaidą toje pačioje funkcijoje, nes negalime tiesiog perduoti klaidos atgalinio skambinimo funkcijai ir ten ją apdoroti. Čia mes tiesiog spausdiname klaidos pranešimą klaidos atveju dėl pavyzdžio.

Užbaigimas

Šiame straipsnyje apžvelgėme įvairius metodus, naudojamus asinchroninei logikai „Javascript“ įdiegti. Pradėjome tyrinėdami konkretų pavyzdį, kodėl turėtume pereiti nuo įprasto sinchroninio programavimo stiliaus prie asinchroninio modelio. Tada perėjome prie atgalinių skambučių, kurie yra pagrindiniai asinchroninio „Javascript“ elementai. Atšaukimų apribojimai paskatino mus rasti įvairių alternatyvų, kurios buvo įtrauktos bėgant metams, siekiant įveikti šiuos apribojimus, daugiausia pažadus ir async/laukti. Asinchroninę logiką galima rasti bet kurioje žiniatinklio vietoje, nesvarbu, ar skambinate išorinei API, inicijuojate duomenų bazės užklausą, rašote į vietinę failų sistemą ar net laukiate vartotojo įvesties prisijungimo formoje. Tikimės, kad dabar jausitės labiau įsitikinę, kad spręsite šias problemas rašydami švarų ir prižiūrimą asinchroninį Javascript!

Jei jums patinka šis straipsnis, peržiūrėkite CLA tinklaraštį, kuriame aptariame įvairias temas, kaip įsitraukti į techniką. Be to, peržiūrėkite mūsų youtube kanalą ir sekite mūsų ankstesnius nemokamus seminarus ir sekite mus socialinėje žiniasklaidoje, kad nepraleistumėte būsimų!


Career Services background pattern

Karjeros paslaugos

Contact Section background image

Palaikykime ryšį

Code Labs Academy © 2024 Visos teisės saugomos.