logo

Callback Hell v JavaScripte

JavaScript je asynchrónny (neblokujúci) a jednovláknový programovací jazyk, čo znamená, že naraz môže byť spustený iba jeden proces.

V programovacích jazykoch sa peklo spätného volania vo všeobecnosti vzťahuje na neefektívny spôsob písania kódu pomocou asynchrónnych volaní. Je známa aj ako pyramída skazy.

Peklo spätného volania v JavaScripte sa označuje ako situácia, keď sa vykonáva nadmerné množstvo vnorených funkcií spätného volania. Znižuje čitateľnosť kódu a údržbu. Pekelná situácia so spätným volaním sa zvyčajne vyskytuje pri práci s asynchrónnymi požiadavkami, ako je vytváranie viacerých požiadaviek API alebo spracovanie udalostí so zložitými závislosťami.

Ak chcete lepšie pochopiť peklo spätných volaní v JavaScripte, najprv pochopte spätné volania a slučky udalostí v JavaScripte.

Spätné volania v JavaScripte

JavaScript považuje všetko za objekt, napríklad reťazce, polia a funkcie. Koncept spätného volania nám teda umožňuje odovzdať funkciu ako argument inej funkcii. Funkcia spätného volania dokončí vykonanie najskôr a nadradená funkcia sa vykoná neskôr.

Funkcie spätného volania sa vykonávajú asynchrónne a umožňujú kódu pokračovať v behu bez čakania na dokončenie asynchrónnej úlohy. Keď sa kombinujú viaceré asynchrónne úlohy a každá úloha závisí od predchádzajúcej úlohy, štruktúra kódu sa skomplikuje.

Poďme pochopiť použitie a dôležitosť spätných volaní. Predpokladajme, že máme funkciu, ktorá má tri parametre, jeden reťazec a dve čísla. Chceme nejaký výstup založený na texte reťazca s viacerými podmienkami.

Zvážte nasledujúci príklad:

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

Výkon:

 30 20 

Vyššie uvedený kód bude fungovať dobre, ale musíme pridať ďalšie úlohy, aby bol kód škálovateľný. Počet podmienených príkazov sa bude tiež neustále zvyšovať, čo povedie k chaotickej štruktúre kódu, ktorú je potrebné optimalizovať a čítať.

Takže môžeme prepísať kód lepším spôsobom takto:

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

Výkon:

 30 20 

Napriek tomu bude výstup rovnaký. Ale vo vyššie uvedenom príklade sme definovali jeho samostatné telo funkcie a odovzdali funkciu ako funkciu spätného volania do funkcie expectResult. Ak teda chceme rozšíriť funkcionalitu očakávaných výsledkov, aby sme mohli vytvoriť ďalšie funkčné telo s inou operáciou a použiť ho ako funkciu spätného volania, uľahčí to pochopenie a zlepší čitateľnosť kódu.

V podporovaných funkciách JavaScriptu sú k dispozícii ďalšie rôzne príklady spätných volaní. Niekoľkými bežnými príkladmi sú poslucháči udalostí a funkcie poľa, ako je mapa, zmenšenie, filter atď.

Aby sme tomu lepšie porozumeli, mali by sme rozumieť prechodovej hodnote a odkazu JavaScriptu.

do while loop java

JavaScript podporuje dva typy dátových typov, ktoré sú primitívne a neprimitívne. Primitívne dátové typy sú nedefinované, null, string a boolean, ktoré sa nedajú zmeniť, alebo môžeme povedať, že sú relatívne nemenné; neprimitívne dátové typy sú polia, funkcie a objekty, ktoré možno meniť alebo meniť.

Pass by reference odovzdáva referenčnú adresu entity, podobne ako funkciu možno brať ako argument. Ak sa teda zmení hodnota v rámci tejto funkcie, zmení sa pôvodná hodnota, ktorá je dostupná mimo funkcie.

V porovnaní s tým koncept pass-by-value nemení svoju pôvodnú hodnotu, ktorá je dostupná mimo tela funkcie. Namiesto toho skopíruje hodnotu na dve rôzne miesta pomocou ich pamäte. JavaScript identifikoval všetky objekty podľa ich referencií.

V JavaScripte addEventListener počúva udalosti ako kliknutie, prejdenie myšou a prejdenie myšou a druhý argument berie ako funkciu, ktorá sa vykoná po spustení udalosti. Táto funkcia sa používa podľa konceptu odkazu a odovzdáva sa bez zátvoriek.

Zvážte nižšie uvedený príklad; v tomto príklade sme odovzdali funkciu pozdravu ako argument do addEventListener ako funkciu spätného volania. Vyvolá sa pri spustení udalosti kliknutia:

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) 

Výkon:

Callback Hell v JavaScripte

Vo vyššie uvedenom príklade sme odovzdali funkciu pozdravu ako argument do addEventListener ako funkciu spätného volania. Vyvolá sa pri spustení udalosti kliknutia.

Podobne je filter aj príkladom funkcie spätného volania. Ak použijeme filter na iteráciu poľa, použije sa iná funkcia spätného volania ako argument na spracovanie údajov poľa. Zvážte príklad nižšie; v tomto príklade používame väčšiu funkciu na vytlačenie čísla väčšieho ako 5 v poli. V metóde filtrovania používame funkciu isGreater ako funkciu spätného volania.

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

Výkon:

 [ 10, 6, 7 ] 

Vyššie uvedený príklad ukazuje, že väčšia funkcia sa používa ako funkcia spätného volania v metóde filtrovania.

Aby sme lepšie porozumeli spätným volaniam, slučkám udalostí v JavaScripte, poďme diskutovať o synchrónnom a asynchrónnom JavaScripte:

Synchrónny JavaScript

Poďme pochopiť, aké sú vlastnosti synchrónneho programovacieho jazyka. Synchrónne programovanie má nasledujúce vlastnosti:

Blokovanie vykonania: Synchrónny programovací jazyk podporuje techniku ​​vykonávania blokovania, čo znamená, že blokuje vykonávanie nasledujúcich príkazov, ktorými sa vykonajú existujúce príkazy. Dosahuje tak predvídateľné a deterministické vykonávanie príkazov.

Sekvenčný tok: Synchrónne programovanie podporuje sekvenčný tok vykonávania, čo znamená, že každý príkaz sa vykonáva sekvenčným spôsobom ako jeden po druhom. Jazykový program čaká na dokončenie výpisu a až potom prejde na ďalší.

jednoduchosť: Synchrónne programovanie sa často považuje za ľahko pochopiteľné, pretože vieme predpovedať jeho poradie toku vykonávania. Vo všeobecnosti je lineárny a ľahko predvídateľný. Malé aplikácie je dobré vyvíjať v týchto jazykoch, pretože dokážu zvládnuť kritické poradie operácií.

Priame spracovanie chýb: V synchrónnom programovacom jazyku je spracovanie chýb veľmi jednoduché. Ak sa pri vykonávaní príkazu vyskytne chyba, vyvolá chybu a program ju môže zachytiť.

Stručne povedané, synchrónne programovanie má dve základné funkcie, t. j. jedna úloha sa vykonáva naraz a ďalšia skupina nasledujúcich úloh sa bude riešiť až po dokončení aktuálnej úlohy. Tým nasleduje sekvenčné vykonávanie kódu.

čo je prípad v sql

Toto správanie programovania, keď sa vykonáva príkaz, jazyk vytvára situáciu blokového kódu, pretože každá úloha musí čakať na dokončenie predchádzajúcej úlohy.

Ale keď ľudia hovoria o JavaScripte, vždy bola záhadná odpoveď, či je synchrónny alebo asynchrónny.

Vo vyššie diskutovaných príkladoch, keď sme použili funkciu ako spätné volanie vo funkcii filtra, bola vykonaná synchrónne. Preto sa to nazýva synchrónne vykonávanie. Funkcia filtra musí počkať, kým väčšia funkcia dokončí svoje vykonávanie.

Preto sa funkcia spätného volania nazýva aj blokovanie spätných volaní, pretože blokuje vykonanie nadradenej funkcie, v ktorej bola vyvolaná.

V prvom rade sa JavaScript považuje za jednovláknový synchrónny a svojou povahou blokujúci. Ale pomocou niekoľkých prístupov môžeme zabezpečiť, aby to fungovalo asynchrónne na základe rôznych scenárov.

Teraz pochopme asynchrónny JavaScript.

Asynchrónny JavaScript

Asynchrónny programovací jazyk sa zameriava na zvýšenie výkonu aplikácie. V takýchto scenároch možno použiť spätné volania. Asynchrónne správanie JavaScriptu môžeme analyzovať na nasledujúcom príklade:

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

Z vyššie uvedeného príkladu funkcia setTimeout berie ako argumenty spätné volanie a čas v milisekundách. Spätné volanie sa vyvolá po uvedenom čase (tu 1s). Stručne povedané, funkcia bude čakať 1 s na svoje vykonanie. Teraz sa pozrite na nižšie uvedený kód:

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

Výkon:

 first Second greet after 1 second 

Z vyššie uvedeného kódu sa správy denníka po uplynutí setTimeout vykonajú ako prvé, kým uplynie časovač. Výsledkom je jedna sekunda a potom uvítacia správa po 1 sekundovom intervale.

V JavaScripte je setTimeout asynchrónna funkcia. Kedykoľvek zavoláme funkciu setTimeout, zaregistruje funkciu spätného volania (v tomto prípade pozdrav), ktorá sa má vykonať po zadanom oneskorení. Neblokuje však vykonanie následného kódu.

Vo vyššie uvedenom príklade sú protokolové správy synchrónne príkazy, ktoré sa vykonajú okamžite. Nie sú závislé od funkcie setTimeout. Preto vykonajú a prihlásia svoje príslušné správy do konzoly bez čakania na oneskorenie špecifikované v setTimeout.

Medzitým slučka udalostí v JavaScripte spracováva asynchrónne úlohy. V tomto prípade čaká, kým uplynie zadané oneskorenie (1 sekunda) a po uplynutí tohto času prijme funkciu spätného volania (pozdrav) a vykoná ju.

Ďalší kód po funkcii setTimeout sa teda spúšťal na pozadí. Toto správanie umožňuje JavaScriptu vykonávať iné úlohy počas čakania na dokončenie asynchrónnej operácie.

Aby sme mohli zvládnuť asynchrónne udalosti v JavaScripte, musíme pochopiť zásobník hovorov a front spätných volaní.

Zvážte nasledujúci obrázok:

Callback Hell v JavaScripte

Z vyššie uvedeného obrázku sa typický JavaScript engine skladá z haldy pamäte a zásobníka hovorov. Zásobník hovorov vykoná celý kód bez čakania, keď sa zatlačí do zásobníka.

Pamäť haldy je zodpovedná za prideľovanie pamäte pre objekty a funkcie za behu, kedykoľvek sú potrebné.

Teraz naše motory prehliadača pozostávajú z niekoľkých webových rozhraní API, ako sú DOM, setTimeout, konzola, načítanie atď., a nástroj môže pristupovať k týmto rozhraniam API pomocou objektu globálneho okna. V ďalšom kroku niektoré slučky udalostí zohrávajú úlohu správcu brány, ktorý vyberá požiadavky na funkcie vo fronte spätných volaní a vkladá ich do zásobníka. Tieto funkcie, ako napríklad setTimeout, vyžadujú určitý čas čakania.

Teraz sa vráťme k nášmu príkladu, funkcii setTimeout; keď sa funkcia stretne, časovač sa zaregistruje vo fronte spätných volaní. Potom sa zvyšok kódu vloží do zásobníka hovorov a vykoná sa, keď funkcia dosiahne limit časovača, vyprší jej platnosť a front spätných volaní odošle funkciu spätného volania, ktorá má špecifikovanú logiku a je zaregistrovaná vo funkcii časového limitu. . Preto sa vykoná po určenom čase.

Scenáre spätného volania do pekla

Teraz sme diskutovali o spätných volaniach, synchrónnych, asynchrónnych a iných dôležitých témach pre peklo spätných volaní. Poďme pochopiť, čo je peklo spätného volania v JavaScripte.

Situácia, keď sú vnorené viaceré spätné volania, sa nazýva peklo spätného volania, pretože tvar kódu vyzerá ako pyramída, ktorá sa tiež nazýva „pyramída skazy“.

Peklo spätného volania sťažuje pochopenie a údržbu kódu. Túto situáciu môžeme väčšinou vidieť pri práci v node JS. Zvážte napríklad nasledujúci príklad:

 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... } }) 

Vo vyššie uvedenom príklade má getUserData používateľské meno, ktoré závisí od zoznamu článkov alebo je potrebné extrahovať odpoveď getArticles, ktorá je v článku. getAddress má tiež podobnú závislosť, ktorá závisí od odpovede getUserData. Táto situácia sa nazýva peklo spätného volania.

Vnútorné fungovanie pekla spätného volania možno pochopiť pomocou nižšie uvedeného príkladu:

Pochopme, že musíme vykonať úlohu A. Na vykonanie úlohy potrebujeme nejaké údaje z úlohy B. Podobne; máme rôzne úlohy, ktoré sú na sebe závislé a vykonávajú sa asynchrónne. Vytvára teda sériu funkcií spätného volania.

Poďme pochopiť Promises v JavaScripte a ako vytvárajú asynchrónne operácie, čo nám umožňuje vyhnúť sa písaniu vnorených spätných volaní.

JavaScript sľubuje

V JavaScripte boli sľuby predstavené v ES6. Ide o objekt so syntaktickým povlakom. Vďaka svojmu asynchrónnemu správaniu je to alternatívny spôsob, ako sa vyhnúť zapisovaniu spätných volaní pre asynchrónne operácie. V súčasnosti sú webové rozhrania API ako fetch() implementované pomocou sľubných, čo poskytuje efektívny spôsob prístupu k údajom zo servera. Tiež zlepšila čitateľnosť kódu a je to spôsob, ako sa vyhnúť písaniu vnorených spätných volaní.

Sľuby v skutočnom živote vyjadrujú dôveru medzi dvoma alebo viacerými osobami a uistenie, že konkrétna vec sa určite stane. V JavaScripte je Promise objekt, ktorý zabezpečuje produkciu jedinej hodnoty v budúcnosti (ak je to potrebné). Promise v JavaScripte sa používa na správu a riešenie asynchrónnych operácií.

Promise vracia objekt, ktorý zabezpečuje a predstavuje dokončenie alebo zlyhanie asynchrónnych operácií a ich výstup. Je to proxy pre hodnotu bez toho, aby poznal presný výstup. Pre asynchrónne akcie je užitočné poskytnúť prípadnú hodnotu úspechu alebo dôvod zlyhania. Asynchrónne metódy teda vracajú hodnoty ako synchrónna metóda.

Vo všeobecnosti majú sľuby tieto tri stavy:

  • Splnené: Stav splnené je, keď bola použitá akcia vyriešená alebo úspešne dokončená.
  • Čaká sa: stav Čaká sa, keď sa žiadosť spracováva a použitá akcia nebola vyriešená ani odmietnutá a je stále vo svojom počiatočnom stave.
  • Odmietnuté: Stav odmietnutia je, keď bola použitá akcia odmietnutá, čo spôsobilo zlyhanie požadovanej operácie. Príčinou odmietnutia môže byť čokoľvek, vrátane výpadku servera.

Syntax sľubov:

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

Nižšie je uvedený príklad písania sľubov:

Toto je príklad napísania sľubu.

vkladanie triediť java
 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)) 

Vo vyššie uvedenom príklade vidíme, ako môžeme efektívne využiť prísľuby na zadanie požiadavky zo servera. Môžeme pozorovať, že čitateľnosť kódu je vo vyššie uvedenom kóde zvýšená ako pri spätných volaniach. Promises poskytujú metódy ako .then() a .catch(), ktoré nám umožňujú zvládnuť stav operácie v prípade úspechu alebo zlyhania. Môžeme špecifikovať prípady pre rôzne stavy prísľubov.

Async/Await v JavaScripte

Je to ďalší spôsob, ako sa vyhnúť používaniu vnorených spätných volaní. Async/ Await nám umožňuje využívať sľuby oveľa efektívnejšie. Reťazeniu metód .then() alebo .catch() sa môžeme vyhnúť. Tieto metódy sú tiež závislé od funkcií spätného volania.

Async/Await možno presne použiť s Promise na zlepšenie výkonu aplikácie. Vnútorne vyriešila sľuby a poskytla výsledok. Tiež je opäť čitateľnejší ako metódy () alebo catch().

Nemôžeme použiť funkciu Async/Await s normálnymi funkciami spätného volania. Aby sme ho mohli použiť, musíme urobiť funkciu asynchrónnou napísaním kľúčového slova async pred kľúčové slovo function. Vnútorne však využíva aj reťazenie.

Nižšie je uvedený príklad funkcie Async/Await:

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

Ak chcete použiť funkciu Async/Await, funkcia musí byť špecifikovaná pomocou kľúčového slova async a kľúčové slovo wait by malo byť napísané vo funkcii. Async zastaví svoju realizáciu, kým sa prísľub nevyrieši alebo nezamietne. Obnoví sa po rozdaní prísľubu. Po vyriešení sa hodnota výrazu wait uloží do premennej, ktorá ho obsahuje.

Zhrnutie:

Stručne povedané, môžeme sa vyhnúť vnoreným spätným volaniam pomocou sľubov a async/wait. Okrem nich môžeme sledovať aj iné prístupy, ako je písanie komentárov a užitočné môže byť aj rozdelenie kódu na samostatné komponenty. V súčasnosti však vývojári uprednostňujú použitie async/wait.

Záver:

Peklo spätného volania v JavaScripte sa označuje ako situácia, keď sa vykonáva nadmerné množstvo vnorených funkcií spätného volania. Znižuje čitateľnosť kódu a údržbu. Pekelná situácia so spätným volaním sa zvyčajne vyskytuje pri práci s asynchrónnymi požiadavkami, ako je vytváranie viacerých požiadaviek API alebo spracovanie udalostí so zložitými závislosťami.

Aby ste lepšie pochopili peklo spätného volania v JavaScripte.

JavaScript považuje všetko za objekt, napríklad reťazce, polia a funkcie. Koncept spätného volania nám teda umožňuje odovzdať funkciu ako argument inej funkcii. Funkcia spätného volania dokončí vykonanie najskôr a nadradená funkcia sa vykoná neskôr.

Funkcie spätného volania sa vykonávajú asynchrónne a umožňujú kódu pokračovať v behu bez čakania na dokončenie asynchrónnej úlohy.