logo

Takaisinsoitto helvetti JavaScriptissä

JavaScript on asynkroninen (ei-esto) ja yksisäikeinen ohjelmointikieli, mikä tarkoittaa, että vain yksi prosessi voidaan suorittaa kerrallaan.

Ohjelmointikielissä takaisinsoitto helvetti tarkoittaa yleensä tehotonta tapaa kirjoittaa koodia asynkronisilla kutsuilla. Se tunnetaan myös tuomion pyramidina.

JavaScriptin takaisinsoitto-helvettiä kutsutaan tilanteeksi, jossa suoritetaan liikaa sisäkkäisiä takaisinsoittotoimintoja. Se vähentää koodin luettavuutta ja ylläpitoa. Takaisinsoitto-helvettitilanne esiintyy tyypillisesti, kun käsitellään asynkronisia pyyntötoimintoja, kuten useiden API-pyyntöjen tekeminen tai monimutkaisten riippuvuuksien tapahtumien käsittely.

Ymmärtääksesi JavaScriptin takaisinkutsuhelvetin paremmin, ymmärrä ensin JavaScriptin takaisinkutsut ja tapahtumasilmukat.

Takaisinsoitto JavaScriptissä

JavaScript pitää kaikkea objektina, kuten merkkijonoja, taulukoita ja toimintoja. Tästä syystä takaisinkutsun käsite antaa meille mahdollisuuden välittää funktion argumenttina toiselle funktiolle. Takaisinsoittotoiminto suorittaa suorituksen ensin ja päätoiminto suoritetaan myöhemmin.

Takaisinsoittotoiminnot suoritetaan asynkronisesti ja sallivat koodin jatkamisen odottamatta asynkronisen tehtävän suorittamista. Kun useita asynkronisia tehtäviä yhdistetään ja jokainen tehtävä riippuu edellisestä tehtävästään, koodirakenteesta tulee monimutkainen.

Ymmärretään takaisinsoittojen käyttö ja merkitys. Oletetaan esimerkissä, että meillä on funktio, joka ottaa kolme parametria, yksi merkkijono ja kaksi numeroa. Haluamme tulosta, joka perustuu merkkijonotekstiin, jossa on useita ehtoja.

Harkitse alla olevaa esimerkkiä:

 function expectedResult(action, x, y){ if(action === 'add'){ return x+y }else if(action === 'subtract'){ return x-y } } console.log(expectedResult('add',20,10)) console.log(expectedResult('subtract',30,10)) 

Lähtö:

 30 20 

Yllä oleva koodi toimii hyvin, mutta meidän on lisättävä tehtäviä, jotta koodista tulee skaalautuva. Myös ehdollisten lauseiden määrä kasvaa jatkuvasti, mikä johtaa sotkuiseen koodirakenteeseen, joka on optimoitava ja luettava.

Joten voimme kirjoittaa koodin uudelleen paremmalla tavalla seuraavasti:

 function add(x,y){ return x+y } function subtract(x,y){ return x-y } function expectedResult(callBack, x, y){ return callBack(x,y) } console.log(expectedResult(add, 20, 10)) console.log(expectedResult(subtract, 30, 10)) 

Lähtö:

 30 20 

Silti tulos on sama. Mutta yllä olevassa esimerkissä olemme määrittäneet sen erillisen funktion rungon ja siirtäneet funktion takaisinkutsun funktiona odotetunResult-funktiolle. Näin ollen, jos haluamme laajentaa odotettujen tulosten toiminnallisuutta niin, että voimme luoda toisen toimivan kappaleen eri toiminnolla ja käyttää sitä takaisinkutsun funktiona, se helpottaa koodin ymmärtämistä ja parantaa koodin luettavuutta.

Tuetuissa JavaScript-ominaisuuksissa on myös muita erilaisia ​​esimerkkejä takaisinkutsuista. Muutamia yleisiä esimerkkejä ovat tapahtumaseuraajat ja taulukkofunktiot, kuten kartoitus, pienennys, suodatus jne.

Ymmärtääksemme sitä paremmin meidän pitäisi ymmärtää JavaScriptin ohitusarvo ja ohitusviite.

JavaScript tukee kahta tietotyyppiä, jotka ovat primitiivisiä ja ei-primitiivisiä. Primitiiviset tietotyypit ovat määrittelemättömiä, null-, merkkijono- ja boolean-arvoja, joita ei voi muuttaa, tai voimme sanoa, että verrattain muuttumattomia; ei-primitiiviset tietotyypit ovat taulukoita, funktioita ja objekteja, joita voidaan muuttaa tai muuttaa.

Pass by reference välittää entiteetin viiteosoitteen, kuten funktiota voidaan pitää argumenttina. Jos siis funktion arvoa muutetaan, se muuttaa alkuperäistä arvoa, joka on käytettävissä funktion ulkopuolella.

Vertailun vuoksi ohitusarvokonsepti ei muuta alkuperäistä arvoaan, joka on käytettävissä funktion rungon ulkopuolella. Sen sijaan se kopioi arvon kahteen eri paikkaan käyttämällä niiden muistia. JavaScript tunnisti kaikki objektit niiden viittauksen perusteella.

JavaScriptissä addEventListener kuuntelee tapahtumia, kuten napsautusta, hiiren siirtoa ja mouseout-toimintoa, ja ottaa toisen argumentin funktiona, joka suoritetaan, kun tapahtuma käynnistetään. Tätä funktiota käytetään viitekäsitteen ohi ja välitetään ilman sulkuja.

Harkitse alla olevaa esimerkkiä; tässä esimerkissä olemme välittäneet tervehdysfunktion argumenttina addEventListeneriin takaisinsoittofunktioksi. Se kutsutaan, kun klikkaustapahtuma käynnistetään:

Test.html:

 Javascript Callback Example <h3>Javascript Callback</h3> Click Here to Console const button = document.getElementById(&apos;btn&apos;); const greet=()=&gt;{ console.log(&apos;Hello, How are you?&apos;) } button.addEventListener(&apos;click&apos;, greet) 

Lähtö:

Palautushelvetti JavaScriptissä

Yllä olevassa esimerkissä olemme välittäneet tervehdysfunktion argumenttina addEventListeneriin takaisinsoittofunktioksi. Se kutsutaan, kun klikkaustapahtuma käynnistetään.

Samoin suodatin on myös esimerkki takaisinsoittotoiminnosta. Jos käytämme suodatinta taulukon iteroimiseen, se ottaa toisen takaisinkutsun funktion argumenttina taulukon tietojen käsittelemiseksi. Harkitse alla olevaa esimerkkiä; tässä esimerkissä käytämme suurempaa funktiota tulostaaksemme taulukossa olevan luvun, joka on suurempi kuin 5. Käytämme isGreater-funktiota takaisinsoittofunktiona suodatinmenetelmässä.

 const arr = [3,10,6,7] const isGreater = num =&gt; num &gt; 5 console.log(arr.filter(isGreater)) 

Lähtö:

 [ 10, 6, 7 ] 

Yllä oleva esimerkki osoittaa, että suurempaa funktiota käytetään takaisinkutsun funktiona suodatinmenetelmässä.

Ymmärtääksesi paremmin JavaScriptin takaisinkutsut, tapahtumasilmukat, keskustellaan synkronisesta ja asynkronisesta JavaScriptistä:

Synkroninen JavaScript

Ymmärrämme, mitkä ovat synkronisen ohjelmointikielen ominaisuudet. Synkronisessa ohjelmoinnissa on seuraavat ominaisuudet:

java lajittelee taulukkoa

Suorituksen estäminen: Synkroninen ohjelmointikieli tukee esto-suoritustekniikkaa, mikä tarkoittaa, että se estää myöhempien lauseiden suorittamisen, ja olemassa olevat käskyt suoritetaan. Näin se saavuttaa lauseiden ennakoitavan ja deterministisen suorituksen.

Peräkkäinen kulku: Synkroninen ohjelmointi tukee peräkkäistä suorituskulkua, mikä tarkoittaa, että jokainen lause suoritetaan peräkkäisellä tavalla kuin yksi toisensa jälkeen. Kieliohjelma odottaa lausunnon valmistumista ennen kuin siirtyy seuraavaan.

Yksinkertaisuus: Usein synkronista ohjelmointia pidetään helposti ymmärrettävänä, koska voimme ennustaa sen suoritusvirran järjestyksen. Yleensä se on lineaarinen ja helppo ennustaa. Pieniä sovelluksia on hyvä kehittää näillä kielillä, koska se pystyy käsittelemään kriittistä toimintojen järjestystä.

Suora virheenkäsittely: Synkronisessa ohjelmointikielessä virheiden käsittely on erittäin helppoa. Jos käskyä suoritettaessa tapahtuu virhe, se antaa virheilmoituksen ja ohjelma voi saada sen kiinni.

Lyhyesti sanottuna synkronisessa ohjelmoinnissa on kaksi ydinominaisuutta, eli yksi tehtävä suoritetaan kerrallaan, ja seuraava joukko seuraavia tehtäviä käsitellään vasta, kun nykyinen tehtävä on suoritettu. Siten se seuraa peräkkäistä koodin suoritusta.

Tämä ohjelmoinnin käyttäytyminen, kun käskyä suoritetaan, kieli luo lohkokooditilanteen, koska jokaisen työn on odotettava edellisen työn valmistumista.

Mutta kun ihmiset puhuvat JavaScriptistä, se on aina ollut hämmentävä vastaus, onko se synkroninen vai asynkroninen.

Yllä käsitellyissä esimerkeissä, kun käytimme funktiota takaisinkutsuna suodatinfunktiossa, se suoritettiin synkronisesti. Siksi sitä kutsutaan synkroniseksi suoritukseksi. Suodatintoiminnon on odotettava suuremman toiminnon suorittamista loppuun.

Tästä syystä takaisinsoittotoimintoa kutsutaan myös takaisinkutsujen estämiseksi, koska se estää sen päätoiminnon suorittamisen, jossa se kutsuttiin.

Ensisijaisesti JavaScriptiä pidetään yksisäikeisenä synkronisena ja estävänä luonteeltaan. Mutta käyttämällä muutamia lähestymistapoja, voimme saada sen toimimaan asynkronisesti eri skenaarioiden perusteella.

Ymmärretään nyt asynkroninen JavaScript.

Asynkroninen JavaScript

Asynkroninen ohjelmointikieli keskittyy parantamaan sovelluksen suorituskykyä. Takaisinsoittoja voidaan käyttää tällaisissa skenaarioissa. Voimme analysoida JavaScriptin asynkronista käyttäytymistä alla olevan esimerkin avulla:

 function greet(){ console.log(&apos;greet after 1 second&apos;) } setTimeout(greet, 1000) 

Yllä olevasta esimerkistä setTimeout-funktio ottaa argumenteiksi takaisinkutsun ja ajan millisekunteina. Takaisinsoitto käynnistyy mainitun ajan kuluttua (tässä 1s). Lyhyesti sanottuna funktio odottaa 1 s suoritustaan. Katso nyt alla olevaa koodia:

 function greet(){ console.log(&apos;greet after 1 second&apos;) } setTimeout(greet, 1000) console.log(&apos;first&apos;) console.log(&apos;Second&apos;) 

Lähtö:

 first Second greet after 1 second 

Yllä olevasta koodista setTimeoutin jälkeiset lokiviestit suoritetaan ensin, kun ajastin kuluu. Tästä syystä tuloksena on yksi sekunti ja sitten tervehdysviesti 1 sekunnin kuluttua.

JavaScriptissä setTimeout on asynkroninen funktio. Aina kun kutsumme setTimeout-funktiota, se rekisteröi takaisinsoittotoiminnon (tässä tapauksessa tervehdys), joka suoritetaan määritetyn viiveen jälkeen. Se ei kuitenkaan estä seuraavan koodin suorittamista.

Yllä olevassa esimerkissä lokiviestit ovat synkronisia käskyjä, jotka suoritetaan välittömästi. Ne eivät ole riippuvaisia ​​setTimeout-toiminnosta. Siksi he suorittavat ja kirjaavat vastaavat viestinsä konsoliin odottamatta setTimeoutissa määritettyä viivettä.

Samaan aikaan JavaScriptin tapahtumasilmukka käsittelee asynkroniset tehtävät. Tässä tapauksessa se odottaa määritetyn viiveen (1 sekunti) kulumista, ja tämän ajan kuluttua se poimii takaisinsoittotoiminnon (tervehdys) ja suorittaa sen.

shilpa shetty ikä

Siten toinen koodi setTimeout-funktion jälkeen suoritettiin ollessaan käynnissä taustalla. Tämä toiminta sallii JavaScriptin suorittaa muita tehtäviä odottaessaan asynkronisen toiminnon valmistumista.

Meidän on ymmärrettävä puhelupino ja takaisinsoittojono käsitelläksemme asynkronisia tapahtumia JavaScriptissä.

Harkitse alla olevaa kuvaa:

Palautushelvetti JavaScriptissä

Yllä olevasta kuvasta tyypillinen JavaScript-moottori koostuu kasamuistista ja puhelupinosta. Kutsupino suorittaa kaiken koodin odottamatta, kun se työnnetään pinoon.

Keon muisti vastaa muistin varaamisesta kohteille ja toiminnoille ajon aikana aina, kun niitä tarvitaan.

Nyt selainmoottorimme koostuvat useista verkkosovellusliittymistä, kuten DOM, setTimeout, konsoli, hae jne., ja moottori voi käyttää näitä API-liittymiä yleisen ikkunaobjektin avulla. Seuraavassa vaiheessa jotkin tapahtumasilmukat toimivat portinvartijana, joka poimii toimintopyynnöt takaisinsoittojonosta ja työntää ne pinoon. Nämä toiminnot, kuten setTimeout, vaativat tietyn odotusajan.

Palataanpa nyt esimerkkiimme, setTimeout-funktioon; kun toiminto havaitaan, ajastin rekisteröidään takaisinsoittojonoon. Tämän jälkeen loput koodista työnnetään puhelupinoon ja suoritetaan, kun toiminto saavuttaa ajastinrajan, se on vanhentunut ja takaisinsoittojono työntää takaisinsoittotoimintoa, jolla on määritetty logiikka ja joka on rekisteröity aikakatkaisutoimintoon. . Siten se suoritetaan määritetyn ajan jälkeen.

Takaisinsoitto Helvetin skenaariot

Nyt olemme keskustelleet takaisinsoittoista, synkronisista, asynkronisista ja muista asiaankuuluvista aiheista takaisinsoittohelvetissä. Ymmärretään, mitä takaisinsoitto helvetti on JavaScriptissä.

Tilanne, jossa useita takaisinsoittoja on sisäkkäin, tunnetaan takaisinsoittohelvenä, koska sen koodimuoto näyttää pyramidilta, jota kutsutaan myös 'tuomion pyramidiksi'.

Takaisinsoittohelvetti vaikeuttaa koodin ymmärtämistä ja ylläpitämistä. Näemme tämän tilanteen useimmiten työskennellessämme solmussa JS. Harkitse esimerkiksi alla olevaa esimerkkiä:

 getArticlesData(20, (articles) =&gt; { console.log(&apos;article lists&apos;, articles); getUserData(article.username, (name) =&gt; { console.log(name); getAddress(name, (item) =&gt; { console.log(item); //This goes on and on... } }) 

Yllä olevassa esimerkissä getUserData ottaa käyttäjänimen, joka on riippuvainen artikkeliluettelosta tai joka täytyy purkaa getArticles-vastaus, joka on artikkelin sisällä. getAddressilla on myös samanlainen riippuvuus, joka riippuu getUserDatan vastauksesta. Tätä tilannetta kutsutaan takaisinsoittohelliksi.

Takaisinsoittohelvetin sisäinen toiminta voidaan ymmärtää alla olevan esimerkin avulla:

Ymmärrämme, että meidän on suoritettava tehtävä A. Tehtävän suorittamiseksi tarvitsemme tietoja tehtävästä B. Samoin; meillä on erilaisia ​​tehtäviä, jotka ovat riippuvaisia ​​toisistaan ​​ja suoritetaan asynkronisesti. Siten se luo sarjan takaisinsoittotoimintoja.

Ymmärretään JavaScriptin lupaukset ja kuinka ne luovat asynkronisia toimintoja, jotta voimme välttää sisäkkäisten takaisinkutsujen kirjoittamisen.

JavaScript lupaa

JavaScriptissä lupaukset esiteltiin ES6:ssa. Se on esine, jolla on syntaktinen pinnoite. Asynkronisen käyttäytymisensä vuoksi se on vaihtoehtoinen tapa välttää takaisinkutsujen kirjoittamista asynkronisille toiminnoille. Nykyään web-sovellusliittymiä, kuten fetch(), toteutetaan lupaavalla tavalla, joka tarjoaa tehokkaan tavan käyttää tietoja palvelimelta. Se myös paransi koodin luettavuutta ja on tapa välttää sisäkkäisten takaisinkutsujen kirjoittamista.

Lupaukset tosielämässä ilmaisevat kahden tai useamman henkilön välistä luottamusta ja varmuutta siitä, että tietty asia varmasti tapahtuu. JavaScriptissä lupaus on objekti, joka varmistaa yhden arvon tuotannon tulevaisuudessa (tarvittaessa). JavaScriptin lupausta käytetään asynkronisten toimintojen hallintaan ja käsittelemiseen.

Lupaus palauttaa objektin, joka varmistaa ja edustaa asynkronisten toimintojen valmistumista tai epäonnistumista ja sen tulosta. Se on arvon välityspalvelin ilman tarkkaa tulosta. Asynkronisille toimille on hyödyllistä antaa mahdollinen onnistumisarvo tai epäonnistumisen syy. Siten asynkroniset menetelmät palauttavat arvot kuten synkroninen menetelmä.

Yleensä lupauksilla on seuraavat kolme tilaa:

  • Täytetty: Täytetty tila on, kun käytetty toiminto on ratkaistu tai suoritettu onnistuneesti.
  • Odottaa: Odottaa-tila on, kun pyyntö on prosessissa ja käytettyä toimintoa ei ole ratkaistu eikä hylätty ja se on edelleen alkuperäisessä tilassaan.
  • Hylätty: Hylätty tila on, kun käytetty toiminto on hylätty, mikä aiheuttaa halutun toiminnon epäonnistumisen. Hylkäämisen syy voi olla mikä tahansa, mukaan lukien palvelimen toimintahäiriö.

Lupausten syntaksi:

 let newPromise = new Promise(function(resolve, reject) { // asynchronous call is made //Resolve or reject the data }); 

Alla on esimerkki lupausten kirjoittamisesta:

Tämä on esimerkki lupauksen kirjoittamisesta.

 function getArticleData(id) { return new Promise((resolve, reject) =&gt; { setTimeout(() =&gt; { console.log(&apos;Fetching data....&apos;); resolve({ id: id, name: &apos;derik&apos; }); }, 5000); }); } getArticleData(&apos;10&apos;).then(res=&gt; console.log(res)) 

Yllä olevassa esimerkissä voimme nähdä, kuinka voimme tehokkaasti käyttää lupauksia pyynnön tekemiseen palvelimelta. Voimme havaita, että koodin luettavuus on parantunut yllä olevassa koodissa kuin takaisinkutsuissa. Promises tarjoaa menetelmiä, kuten .then() ja .catch(), joiden avulla voimme käsitellä toiminnan tilaa onnistumisen tai epäonnistumisen tapauksessa. Voimme määritellä tapaukset lupausten eri tiloihin.

Async/Await JavaScriptissä

Se on toinen tapa välttää sisäkkäisten takaisinkutsujen käyttöä. Async/ Await antaa meille mahdollisuuden käyttää lupauksia paljon tehokkaammin. Voimme välttää .then()- tai .catch()-metodin ketjutusta. Nämä menetelmät ovat myös riippuvaisia ​​takaisinsoittotoiminnoista.

Async/Awaitia voidaan käyttää tarkasti Promisen kanssa sovelluksen suorituskyvyn parantamiseksi. Se ratkaisi sisäisesti lupaukset ja toi tuloksen. Lisäksi se on jälleen luettavampi kuin ()- tai catch()-menetelmät.

Emme voi käyttää Async/Await-toimintoa tavallisten takaisinsoittotoimintojen kanssa. Käyttääksemme sitä meidän on tehtävä funktio asynkroniseksi kirjoittamalla asynkroninen avainsana ennen funktion avainsanaa. Sisäisesti se käyttää kuitenkin myös ketjutusta.

Alla on esimerkki Async/Awaitista:

 async function displayData() { try { const articleData = await getArticle(10); const placeData = await getPlaces(article.name); const cityData = await getCity(place) console.log(city); } catch (err) { console.log(&apos;Error: &apos;, err.message); } } displayData(); 

Käyttääksesi Async/Await-funktiota, funktio on määritettävä async-avainsanalla ja await-avainsana tulee kirjoittaa funktion sisään. Async lopettaa sen suorittamisen, kunnes Lupaus on ratkaistu tai hylätty. Sitä jatketaan, kun lupaus on lunastettu. Kun se on ratkaistu, odotuslausekkeen arvo tallennetaan muuttujaan, jossa se on.

Yhteenveto:

Lyhyesti sanottuna voimme välttää sisäkkäisiä takaisinsoittoja käyttämällä lupauksia ja async/wait-toimintoa. Näiden lisäksi voimme seurata muita lähestymistapoja, kuten kommenttien kirjoittamista, ja koodin jakaminen erillisiin osiin voi myös olla hyödyllistä. Mutta nykyään kehittäjät käyttävät mieluummin async/await-toimintoa.

Johtopäätös:

JavaScriptin takaisinsoitto-helvettiä kutsutaan tilanteeksi, jossa suoritetaan liikaa sisäkkäisiä takaisinsoittotoimintoja. Se vähentää koodin luettavuutta ja ylläpitoa. Takaisinsoitto-helvettitilanne esiintyy tyypillisesti, kun käsitellään asynkronisia pyyntötoimintoja, kuten useiden API-pyyntöjen tekeminen tai monimutkaisten riippuvuuksien tapahtumien käsittely.

Ymmärtääksesi paremmin JavaScriptin takaisinsoittohelvetin.

JavaScript pitää kaikkea objektina, kuten merkkijonoja, taulukoita ja toimintoja. Tästä syystä takaisinkutsun käsite antaa meille mahdollisuuden välittää funktion argumenttina toiselle funktiolle. Takaisinsoittotoiminto suorittaa suorituksen ensin ja päätoiminto suoritetaan myöhemmin.

Takaisinsoittotoiminnot suoritetaan asynkronisesti ja sallivat koodin jatkamisen odottamatta asynkronisen tehtävän suorittamista.