JavaScript er et asynkront (ikke-blokerende) og enkelt-trådet programmeringssprog, hvilket betyder, at kun én proces kan køres ad gangen.
I programmeringssprog refererer tilbagekaldshelvede generelt til en ineffektiv måde at skrive kode på med asynkrone opkald. Det er også kendt som Doom-pyramiden.
Tilbagekaldshelvede i JavaScript omtales som en situation, hvor en overdreven mængde af indlejrede tilbagekaldsfunktioner udføres. Det reducerer kodelæsbarhed og vedligeholdelse. Tilbagekaldshelvede-situationen opstår typisk, når man beskæftiger sig med asynkrone anmodningsoperationer, såsom at lave flere API-anmodninger eller håndtere hændelser med komplekse afhængigheder.
For bedre at forstå tilbagekaldshelvede i JavaScript, skal du først forstå tilbagekaldene og hændelsesløkkerne i JavaScript.
Tilbagekald i JavaScript
JavaScript betragter alt som et objekt, såsom strenge, arrays og funktioner. Derfor giver callback-konceptet os mulighed for at videregive funktionen som et argument til en anden funktion. Tilbagekaldsfunktionen vil fuldføre udførelsen først, og den overordnede funktion vil blive udført senere.
Tilbagekaldsfunktionerne udføres asynkront og tillader koden at fortsætte med at køre uden at vente på at fuldføre den asynkrone opgave. Når flere asynkrone opgaver kombineres, og hver opgave afhænger af dens tidligere opgave, bliver kodestrukturen kompliceret.
Lad os forstå brugen og vigtigheden af tilbagekaldene. Lad os antage et eksempel, vi har en funktion, der tager tre parametre, en streng og to tal. Vi ønsker noget output baseret på strengteksten med flere betingelser.
Overvej nedenstående eksempel:
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))
Produktion:
30 20
Ovenstående kode vil fungere fint, men vi er nødt til at tilføje flere opgaver for at gøre koden skalerbar. Antallet af betingede udsagn vil også blive ved med at stige, hvilket vil føre til en rodet kodestruktur, der skal optimeres og læses.
q2 måneder
Så vi kan omskrive koden på en bedre måde som følger:
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))
Produktion:
30 20
Alligevel vil outputtet være det samme. Men i ovenstående eksempel har vi defineret dets separate funktionslegeme og videregivet funktionen som en tilbagekaldsfunktion til funktionen forventet Resultat. Derfor, hvis vi ønsker at udvide funktionaliteten af de forventede resultater, så vi kan oprette et andet fungerende organ med en anden operation og bruge det som tilbagekaldsfunktion, vil det gøre det lettere at forstå og forbedre kodens læsbarhed.
Der er andre forskellige eksempler på tilbagekald, der er tilgængelige i understøttede JavaScript-funktioner. Et par almindelige eksempler er begivenhedslyttere og array-funktioner såsom kort, reducere, filtrere osv.
For bedre at forstå det, bør vi forstå JavaScripts pass-by-value og pass-by-reference.
JavaScript understøtter to typer datatyper, som er primitive og ikke-primitive. Primitive datatyper er undefined, null, string og boolean, som ikke kan ændres, eller vi kan sige uforanderlige sammenlignende; ikke-primitive datatyper er arrays, funktioner og objekter, som kan ændres eller ændres.
Pass by reference videregiver referenceadressen for en enhed, ligesom en funktion kan tages som et argument. Så hvis værdien i denne funktion ændres, vil den ændre den oprindelige værdi, som er tilgængelig uden for funktionen.
Til sammenligning ændrer begrebet pass-by-value ikke sin oprindelige værdi, som er tilgængelig uden for funktionslegemet. I stedet vil den kopiere værdien til to forskellige steder ved at bruge deres hukommelse. JavaScript identificerede alle objekterne ved deres reference.
I JavaScript lytter addEventListener efter hændelser såsom klik, mouseover og mouseout og tager det andet argument som en funktion, der vil blive udført, når hændelsen er udløst. Denne funktion bruges forbi referencekonceptet og bestået uden parentes.
Overvej nedenstående eksempel; i dette eksempel har vi sendt en hilsen-funktion som et argument ind i addEventListener som tilbagekaldsfunktionen. Den vil blive påkaldt, når klikhændelsen udløses:
Test.html:
Javascript Callback Example <h3>Javascript Callback</h3> Click Here to Console const button = document.getElementById('btn'); const greet=()=>{ console.log('Hello, How are you?') } button.addEventListener('click', greet)
Produktion:
I ovenstående eksempel har vi sendt en hilsen-funktion som et argument ind i addEventListener som tilbagekaldsfunktionen. Den vil blive aktiveret, når klikhændelsen udløses.
På samme måde er filteret også et eksempel på tilbagekaldsfunktionen. Hvis vi bruger et filter til at iterere et array, vil det tage en anden tilbagekaldsfunktion som et argument for at behandle array-dataene. Overvej eksemplet nedenfor; i dette eksempel bruger vi funktionen større til at udskrive tallet større end 5 i arrayet. Vi bruger isGreater-funktionen som en tilbagekaldsfunktion i filtermetoden.
const arr = [3,10,6,7] const isGreater = num => num > 5 console.log(arr.filter(isGreater))
Produktion:
[ 10, 6, 7 ]
Ovenstående eksempel viser, at den større funktion bruges som en tilbagekaldsfunktion i filtermetoden.
For bedre at forstå tilbagekald, hændelsesløkker i JavaScript, lad os diskutere synkron og asynkron JavaScript:
Synkron JavaScript
Lad os forstå, hvad der er funktionerne i et synkront programmeringssprog. Synkron programmering har følgende funktioner:
Blokerende udførelse: Det synkrone programmeringssprog understøtter blokeringsudførelsesteknikken, hvilket betyder, at det blokerer udførelsen af efterfølgende udsagn, de eksisterende udsagn vil blive eksekveret. Dermed opnås den forudsigelige og deterministiske udførelse af udsagn.
Sekventielt flow: Synkron programmering understøtter det sekventielle flow af eksekvering, hvilket betyder, at hver sætning udføres på en sekventiel måde som den ene efter den anden. Sprogprogrammet venter på, at en erklæring er færdig, før den går videre til den næste.
Enkelhed: Ofte betragtes den synkrone programmering som let at forstå, fordi vi kan forudsige dens rækkefølge af eksekveringsflowet. Generelt er det lineært og nemt at forudsige. De små applikationer er gode at udvikle på disse sprog, fordi de kan håndtere den kritiske rækkefølge af operationer.
Direkte fejlhåndtering: I et synkront programmeringssprog er fejlhåndtering meget let. Hvis der opstår en fejl, når en sætning udføres, vil den give en fejl, og programmet kan fange den.
I en nøddeskal har synkron programmering to kernefunktioner, det vil sige, at en enkelt opgave udføres ad gangen, og det næste sæt af følgende opgaver vil først blive behandlet, når den aktuelle opgave er afsluttet. Derved følger den en sekventiel kodeeksekvering.
mylivecricket ind
Denne opførsel af programmeringen, når en sætning udføres, skaber en situation med blokkode, da hvert job skal vente på, at det forrige job bliver fuldført.
Men når folk taler om JavaScript, har det altid været et gådefuldt svar, uanset om det er synkront eller asynkront.
I de ovenfor omtalte eksempler, når vi brugte en funktion som tilbagekald i filterfunktionen, blev den eksekveret synkront. Derfor kaldes det en synkron udførelse. Filterfunktionen skal vente på, at den større funktion afslutter sin udførelse.
Derfor kaldes tilbagekaldsfunktionen også blokering af tilbagekald, da den blokerer udførelsen af den overordnede funktion, hvor den blev påkaldt.
Primært betragtes JavaScript som enkelttrådssynkront og blokerende. Men ved at bruge nogle få tilgange kan vi få det til at fungere asynkront baseret på forskellige scenarier.
Lad os nu forstå det asynkrone JavaScript.
Asynkron JavaScript
Det asynkrone programmeringssprog fokuserer på at forbedre applikationens ydeevne. Tilbagekaldene kan bruges i sådanne scenarier. Vi kan analysere den asynkrone adfærd af JavaScript ved hjælp af nedenstående eksempel:
function greet(){ console.log('greet after 1 second') } setTimeout(greet, 1000)
Fra ovenstående eksempel tager funktionen setTimeout et tilbagekald og tid i millisekunder som argumenter. Tilbagekaldet bliver påkaldt efter det nævnte tidspunkt (her 1s). Kort sagt vil funktionen vente i 1 sekunder på dens udførelse. Tag nu et kig på nedenstående kode:
heap-sorteringsalgoritme
function greet(){ console.log('greet after 1 second') } setTimeout(greet, 1000) console.log('first') console.log('Second')
Produktion:
first Second greet after 1 second
Fra ovenstående kode vil logmeddelelserne efter setTimeout blive udført først, mens timeren vil passere. Derfor resulterer det i et sekund og derefter en hilsen efter 1 sekunds tidsinterval.
I JavaScript er setTimeout en asynkron funktion. Hver gang vi kalder setTimeout-funktionen, registrerer den en tilbagekaldsfunktion (greet i dette tilfælde), der skal udføres efter den angivne forsinkelse. Det blokerer dog ikke for udførelsen af den efterfølgende kode.
I ovenstående eksempel er logmeddelelserne de synkrone sætninger, der udføres med det samme. De er ikke afhængige af setTimeout-funktionen. Derfor udfører og logger de deres respektive beskeder til konsollen uden at vente på forsinkelsen angivet i setTimeout.
I mellemtiden håndterer begivenhedsløkken i JavaScript de asynkrone opgaver. I dette tilfælde venter den på, at den angivne forsinkelse (1 sekund) er gået, og efter den tid er gået, opfanger den tilbagekaldsfunktionen (greet) og udfører den.
Den anden kode efter setTimeout-funktionen kørte således, mens den kørte i baggrunden. Denne adfærd gør det muligt for JavaScript at udføre andre opgaver, mens man venter på, at den asynkrone handling er fuldført.
Vi skal forstå opkaldsstakken og tilbagekaldskøen for at håndtere de asynkrone hændelser i JavaScript.
Overvej billedet nedenfor:
Fra ovenstående billede består en typisk JavaScript-motor af en heap-hukommelse og en opkaldsstak. Opkaldsstakken udfører al koden uden at vente, når den skubbes til stakken.
Heap-hukommelsen er ansvarlig for at allokere hukommelsen til objekter og funktioner under kørsel, når de er nødvendige.
Nu består vores browsermotorer af flere web-API'er såsom DOM, setTimeout, console, fetch osv., og motoren kan få adgang til disse API'er ved hjælp af det globale vinduesobjekt. I det næste trin spiller nogle hændelsesløkker rollen som gatekeeper, der vælger funktionsanmodninger inde i tilbagekaldskøen og skubber dem ind i stakken. Disse funktioner, såsom setTimeout, kræver en vis ventetid.
Lad os nu gå tilbage til vores eksempel, setTimeout-funktionen; når funktionen bliver stødt på, bliver timeren registreret i tilbagekaldskøen. Herefter skubbes resten af koden ind i opkaldsstakken og bliver udført, når funktionen når sin timergrænse, den er udløbet, og tilbagekaldskøen skubber tilbagekaldsfunktionen, som har den angivne logik og er registreret i timeout-funktionen . Det vil således blive udført efter det angivne tidspunkt.
Callback Hell Scenarier
Nu har vi diskuteret tilbagekald, synkrone, asynkrone og andre relevante emner for tilbagekaldshelvede. Lad os forstå, hvad tilbagekaldshelvede er i JavaScript.
Situationen, hvor flere tilbagekald er indlejret, er kendt som tilbagekaldshelvede, da dens kodeform ligner en pyramide, som også kaldes 'undergangspyramiden'.
Tilbagekaldshelvedet gør det sværere at forstå og vedligeholde koden. Vi kan for det meste se denne situation, mens vi arbejder i node JS. Overvej for eksempel nedenstående eksempel:
getArticlesData(20, (articles) => { console.log('article lists', articles); getUserData(article.username, (name) => { console.log(name); getAddress(name, (item) => { console.log(item); //This goes on and on... } })
I ovenstående eksempel tager getUserData et brugernavn, der er afhængigt af artikellisten eller skal udtrækkes getArticles-svar, som er inde i artiklen. getAddress har også en lignende afhængighed, som er afhængig af getUserDatas svar. Denne situation kaldes tilbagekaldshelvede.
Den interne funktion af tilbagekaldshelvedet kan forstås med nedenstående eksempel:
Lad os forstå, at vi skal udføre opgave A. For at udføre en opgave har vi brug for nogle data fra opgaven B. På samme måde; vi har forskellige opgaver, der er afhængige af hinanden og udfører asynkront. Det skaber således en række tilbagekaldsfunktioner.
Lad os forstå løfterne i JavaScript, og hvordan de skaber asynkrone operationer, så vi kan undgå at skrive indlejrede tilbagekald.
JavaScript lover
I JavaScript blev løfter introduceret i ES6. Det er en genstand med en syntaktisk belægning. På grund af dets asynkrone opførsel er det en alternativ måde at undgå at skrive tilbagekald for asynkrone operationer. I dag implementeres web-API'er som fetch() ved hjælp af det lovende, som giver en effektiv måde at få adgang til dataene fra serveren på. Det forbedrede også kodelæsbarheden og er en måde at undgå at skrive indlejrede tilbagekald på.
Løfter i det virkelige liv udtrykker tillid mellem to eller flere personer og en forsikring om, at en bestemt ting helt sikkert vil ske. I JavaScript er et løfte et objekt, som sikrer at producere en enkelt værdi i fremtiden (når det kræves). Promise i JavaScript bruges til at administrere og tackle asynkrone operationer.
Løftet returnerer et objekt, som sikrer og repræsenterer fuldførelsen eller fejlen af asynkrone operationer og dets output. Det er en proxy for en værdi uden at kende det nøjagtige output. Det er nyttigt for asynkrone handlinger at give en eventuel succesværdi eller fejlårsag. Således returnerer de asynkrone metoder værdierne som en synkron metode.
Generelt har løfterne følgende tre tilstande:
- Opfyldt: Opfyldt tilstand er, når en anvendt handling er blevet løst eller fuldført med succes.
- Afventer: Afventende tilstand er, når anmodningen er i gang, og den anvendte handling hverken er blevet løst eller afvist og stadig er i sin oprindelige tilstand.
- Afvist: Den afviste tilstand er, når den anvendte handling er blevet afvist, hvilket får den ønskede handling til at mislykkes. Årsagen til afvisningen kan være hvad som helst, herunder at serveren er nede.
Syntaksen for løfterne:
let newPromise = new Promise(function(resolve, reject) { // asynchronous call is made //Resolve or reject the data });
Nedenfor er et eksempel på at skrive løfterne:
Dette er et eksempel på at skrive et løfte.
function getArticleData(id) { return new Promise((resolve, reject) => { setTimeout(() => { console.log('Fetching data....'); resolve({ id: id, name: 'derik' }); }, 5000); }); } getArticleData('10').then(res=> console.log(res))
I ovenstående eksempel kan vi se, hvordan vi effektivt kan bruge løfterne til at lave en anmodning fra serveren. Vi kan observere, at kodelæsbarheden er øget i ovenstående kode end i tilbagekaldene. Løfter giver metoder som .then() og .catch(), som giver os mulighed for at håndtere operationsstatus i tilfælde af succes eller fiasko. Vi kan specificere sagerne for løfternes forskellige tilstande.
Async/Await i JavaScript
Det er en anden måde at undgå brugen af indlejrede tilbagekald. Async/ Await giver os mulighed for at bruge løfterne meget mere effektivt. Vi kan undgå at bruge .then() eller .catch() metodekæde. Disse metoder er også afhængige af tilbagekaldsfunktionerne.
Async/Await kan bruges præcist med Promise for at forbedre applikationens ydeevne. Det løste løfterne internt og leverede resultatet. Også igen, det er mere læsbart end () eller catch() metoderne.
Vi kan ikke bruge Async/Await med de normale tilbagekaldsfunktioner. For at bruge det skal vi gøre en funktion asynkron ved at skrive et asynkront nøgleord før funktionsnøgleordet. Men internt bruger den også chaining.
Nedenfor er et eksempel på 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('Error: ', err.message); } } displayData();
For at bruge Async/Await skal funktionen angives med async nøgleordet, og await nøgleordet skal skrives inde i funktionen. Asynkroniseringen stopper sin eksekvering, indtil løftet er løst eller afvist. Det vil blive genoptaget, når løftet er givet. Når det er løst, vil værdien af afvent-udtrykket blive gemt i den variabel, der indeholder det.
Resumé:
I en nøddeskal kan vi undgå indlejrede tilbagekald ved at bruge løfterne og asynkronisere/afvente. Bortset fra disse kan vi følge andre tilgange, såsom at skrive kommentarer, og det kan også være nyttigt at opdele koden i separate komponenter. Men i dag foretrækker udviklerne brugen af async/await.
Konklusion:
Tilbagekaldshelvede i JavaScript omtales som en situation, hvor en overdreven mængde af indlejrede tilbagekaldsfunktioner udføres. Det reducerer kodelæsbarhed og vedligeholdelse. Tilbagekaldshelvede-situationen opstår typisk, når man beskæftiger sig med asynkrone anmodningsoperationer, såsom at lave flere API-anmodninger eller håndtere hændelser med komplekse afhængigheder.
ms word hurtig adgang værktøjslinje
For bedre at forstå tilbagekaldshelvede i JavaScript.
JavaScript betragter alt som et objekt, såsom strenge, arrays og funktioner. Derfor giver callback-konceptet os mulighed for at videregive funktionen som et argument til en anden funktion. Tilbagekaldsfunktionen vil fuldføre udførelsen først, og den overordnede funktion vil blive udført senere.
Tilbagekaldsfunktionerne udføres asynkront og tillader koden at fortsætte med at køre uden at vente på at fuldføre den asynkrone opgave.