JavaScript és un llenguatge de programació asíncron (no bloquejant) i d'un sol fil, el que significa que només es pot executar un procés alhora.
En llenguatges de programació, l'infern de devolució de trucada generalment es refereix a una manera ineficaç d'escriure codi amb trucades asíncrones. També es coneix com la Piràmide de la Perdició.
L'infern de devolució de trucada a JavaScript es coneix com una situació en què s'està executant una quantitat excessiva de funcions de devolució de trucada imbricades. Redueix la llegibilitat i el manteniment del codi. La situació d'infern de devolució de trucada es produeix normalment quan es tracta d'operacions de sol·licituds asíncrones, com ara fer diverses sol·licituds d'API o gestionar esdeveniments amb dependències complexes.
Per entendre millor l'infern de devolució de trucada a JavaScript, primer enteneu les devolucions de trucada i els bucles d'esdeveniments a JavaScript.
Devolució de trucades en JavaScript
JavaScript ho considera tot com un objecte, com ara cadenes, matrius i funcions. Per tant, el concepte de devolució de trucada ens permet passar la funció com a argument a una altra funció. La funció de devolució de trucada completarà l'execució primer i la funció principal s'executarà més tard.
Les funcions de devolució de trucada s'executen de manera asíncrona i permeten que el codi continuï executant-se sense esperar a completar la tasca asíncrona. Quan es combinen diverses tasques asíncrones i cada tasca depèn de la seva tasca anterior, l'estructura del codi es complica.
Entenem l'ús i la importància de les devolució de trucades. Suposem que, per exemple, tenim una funció que pren tres paràmetres, una cadena i dos números. Volem una sortida basada en el text de la cadena amb diverses condicions.
Considereu l'exemple següent:
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))
Sortida:
30 20
El codi anterior funcionarà bé, però hem d'afegir més tasques perquè el codi sigui escalable. El nombre de declaracions condicionals també seguirà augmentant, la qual cosa donarà lloc a una estructura de codi desordenada que s'ha d'optimitzar i llegir.
Per tant, podem reescriure el codi d'una manera millor de la següent manera:
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))
Sortida:
30 20
Tot i així, la sortida serà la mateixa. Però a l'exemple anterior, hem definit el seu cos de funció independent i hem passat la funció com a funció de devolució de trucada a la funció Resultat esperat. Per tant, si volem ampliar la funcionalitat dels resultats esperats perquè puguem crear un altre cos funcional amb una operació diferent i utilitzar-lo com a funció de devolució de trucada, serà més fàcil entendre i millorar la llegibilitat del codi.
Hi ha altres exemples diferents de les devolucions de trucada disponibles a les funcions de JavaScript compatibles. Alguns exemples habituals són els oients d'esdeveniments i les funcions de matriu com ara mapa, reduir, filtrar, etc.
Per entendre-ho millor, hauríem d'entendre el pas per valor i la referència de JavaScript.
JavaScript admet dos tipus de tipus de dades que són primitius i no primitius. Els tipus de dades primitives són indefinits, nuls, de cadena i booleans, que no es poden canviar, o podem dir que són immutables comparativament; Els tipus de dades no primitius són matrius, funcions i objectes que es poden canviar o modificar.
Pass per referència passa l'adreça de referència d'una entitat, com una funció es pot prendre com a argument. Per tant, si es canvia el valor dins d'aquesta funció, alterarà el valor original, que està disponible fora de la funció.
En comparació, el concepte de transmissió per valor no canvia el seu valor original, que està disponible fora del cos de la funció. En canvi, copiarà el valor en dues ubicacions diferents utilitzant la seva memòria. JavaScript va identificar tots els objectes per la seva referència.
A JavaScript, l'addEventListener escolta els esdeveniments com ara fer clic, passar el ratolí i sortir del ratolí i pren el segon argument com a funció que s'executarà un cop s'hagi activat l'esdeveniment. Aquesta funció s'utilitza per concepte de referència i es passa sense parèntesis.
Considereu l'exemple següent; en aquest exemple, hem passat una funció de salutació com a argument a addEventListener com a funció de devolució de trucada. S'invocarà quan s'activa l'esdeveniment de clic:
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)
Sortida:
A l'exemple anterior, hem passat una funció de salutació com a argument a addEventListener com a funció de devolució de trucada. S'invocarà quan s'activa l'esdeveniment de clic.
De la mateixa manera, el filtre també és un exemple de la funció de devolució de trucada. Si fem servir un filtre per iterar una matriu, caldrà una altra funció de devolució de trucada com a argument per processar les dades de la matriu. Considereu l'exemple següent; en aquest exemple, estem utilitzant la funció major per imprimir el nombre més gran que 5 a la matriu. Estem utilitzant la funció isGreater com a funció de devolució de trucada al mètode de filtre.
const arr = [3,10,6,7] const isGreater = num => num > 5 console.log(arr.filter(isGreater))
Sortida:
[ 10, 6, 7 ]
L'exemple anterior mostra que la funció major s'utilitza com a funció de devolució de trucada en el mètode de filtre.
Per entendre millor les devolucions de trucada, els bucles d'esdeveniments a JavaScript, parlem de JavaScript síncron i asíncron:
JavaScript síncron
Entendrem quines són les característiques d'un llenguatge de programació síncrona. La programació síncrona té les següents característiques:
Bloqueig de l'execució: El llenguatge de programació síncrona admet la tècnica d'execució de bloqueig, que vol dir que bloqueja l'execució de sentències posteriors que s'executaran les sentències existents. Així s'aconsegueix l'execució predictible i determinista de les sentències.
instància de java
Flux seqüencial: La programació síncrona admet el flux d'execució seqüencial, el que significa que cada instrucció s'executa de manera seqüencial com una darrere l'altra. El programa d'idioma espera que es completi una declaració abans de passar a la següent.
Senzillesa: Sovint, la programació síncrona es considera fàcil d'entendre perquè podem predir el seu ordre del flux d'execució. En general, és lineal i fàcil de predir. Les petites aplicacions són bones per desenvolupar-se en aquests llenguatges perquè poden gestionar l'ordre crític de les operacions.
Tractament directe d'errors: En un llenguatge de programació síncron, el maneig d'errors és molt fàcil. Si es produeix un error quan s'està executant una instrucció, generarà un error i el programa el podrà detectar.
En poques paraules, la programació síncrona té dues característiques bàsiques, és a dir, s'executa una única tasca alhora, i el següent conjunt de tasques següents només s'abordarà un cop s'hagi acabat la tasca actual. Per tant, segueix una execució de codi seqüencial.
Aquest comportament de la programació quan s'està executant una instrucció, el llenguatge crea una situació de codi de bloc ja que cada treball ha d'esperar a que es completi el treball anterior.
Però quan la gent parla de JavaScript, sempre ha estat una resposta desconcertant tant si és sincrònic com asincrònic.
En els exemples comentats anteriorment, quan vam utilitzar una funció com a devolució de trucada a la funció de filtre, s'executava de manera sincrònica. Per tant, s'anomena execució síncrona. La funció de filtre ha d'esperar que la funció major acabi la seva execució.
Per tant, la funció de devolució de trucada també s'anomena bloquejar les devolucions de trucada, ja que bloqueja l'execució de la funció principal en la qual es va invocar.
Principalment, JavaScript es considera sincrònic d'un sol fil i de naturalesa de bloqueig. Però utilitzant alguns enfocaments, podem fer que funcioni de manera asíncrona en funció de diferents escenaris.
Ara, anem a entendre el JavaScript asíncron.
JavaScript asíncron
El llenguatge de programació asíncron se centra en millorar el rendiment de l'aplicació. Les devolució de trucades es poden utilitzar en aquests escenaris. Podem analitzar el comportament asíncron de JavaScript amb l'exemple següent:
function greet(){ console.log('greet after 1 second') } setTimeout(greet, 1000)
A partir de l'exemple anterior, la funció setTimeout té com a arguments una devolució de trucada i un temps en mil·lisegons. La devolució de trucada s'invoca després del temps esmentat (aquí 1s). En poques paraules, la funció esperarà 1 s per a la seva execució. Ara, mireu el codi següent:
function greet(){ console.log('greet after 1 second') } setTimeout(greet, 1000) console.log('first') console.log('Second')
Sortida:
first Second greet after 1 second
A partir del codi anterior, els missatges de registre després del setTimeout s'executaran primer mentre passa el temporitzador. Per tant, resulta un segon i després el missatge de salutació després d'un interval de temps d'1 segon.
A JavaScript, setTimeout és una funció asíncrona. Sempre que cridem a la funció setTimeout, registra una funció de devolució de trucada (salut en aquest cas) que s'executarà després del retard especificat. Tanmateix, no bloqueja l'execució del codi posterior.
A l'exemple anterior, els missatges de registre són les sentències sincròniques que s'executen immediatament. No depenen de la funció setTimeout. Per tant, executen i registren els seus respectius missatges a la consola sense esperar el retard especificat a setTimeout.
Mentrestant, el bucle d'esdeveniments a JavaScript gestiona les tasques asíncrones. En aquest cas, espera que passi el retard especificat (1 segon) i, passat aquest temps, agafa la funció de devolució de trucada (salut) i l'executa.
Així, l'altre codi després de la funció setTimeout s'estava executant mentre s'executava en segon pla. Aquest comportament permet a JavaScript realitzar altres tasques mentre s'espera que finalitzi l'operació asíncrona.
Hem d'entendre la pila de trucades i la cua de devolució de trucades per gestionar els esdeveniments asíncrons a JavaScript.
Considereu la imatge següent:
programa de matriu bidimensional en c
A la imatge de dalt, un motor JavaScript típic consta d'una memòria de pila i una pila de trucades. La pila de trucades executa tot el codi sense esperar quan es posa a la pila.
La memòria de pila s'encarrega d'assignar la memòria per als objectes i funcions en temps d'execució sempre que siguin necessàries.
Ara, els nostres motors de navegador consisteixen en diverses API web com ara DOM, setTimeout, console, fetch, etc., i el motor pot accedir a aquestes API mitjançant l'objecte finestra global. En el següent pas, alguns bucles d'esdeveniments fan el paper de porter que recull les sol·licituds de funció dins de la cua de devolució de trucada i les empènyer a la pila. Aquestes funcions, com ara setTimeout, requereixen un temps d'espera determinat.
Ara, tornem al nostre exemple, la funció setTimeout; quan es troba la funció, el temporitzador es registra a la cua de devolució de trucada. Després d'això, la resta del codi s'envia a la pila de trucades i s'executa una vegada que la funció arriba al seu límit de temporitzador, ha caducat i la cua de devolució de trucada impulsa la funció de devolució de trucada, que té la lògica especificada i es registra a la funció de temps d'espera. . Per tant, s'executarà després del temps especificat.
Escenaris de l'infern de retorn de trucada
Ara, hem parlat de les devolucions de trucada, sincròniques, asíncrones i altres temes rellevants per a l'infern de la devolució de trucades. Entenem què és l'infern de devolució de trucada a JavaScript.
La situació en què hi ha múltiples devolucions de trucada imbricades es coneix com l'infern de la devolució de trucada, ja que la seva forma de codi sembla una piràmide, que també s'anomena 'piràmide de la perdició'.
L'infern de devolució de trucada fa que sigui més difícil entendre i mantenir el codi. Majoritàriament podem veure aquesta situació mentre treballem al node JS. Per exemple, considereu l'exemple següent:
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... } })
A l'exemple anterior, getUserData pren un nom d'usuari que depèn de la llista d'articles o s'ha d'extreure la resposta de getArticles que es troba dins de l'article. getAddress també té una dependència similar, que depèn de la resposta de getUserData. Aquesta situació s'anomena infern de devolució de trucades.
El funcionament intern de l'infern de devolució de trucada es pot entendre amb l'exemple següent:
Entenem que hem de realitzar la tasca A. Per realitzar una tasca, necessitem algunes dades de la tasca B. De manera similar; tenim diferents tasques que depenen les unes de les altres i s'executen de manera asíncrona. Per tant, crea una sèrie de funcions de devolució de trucada.
Entenem les Promeses en JavaScript i com creen operacions asíncrones, cosa que ens permet evitar escriure devolucions de trucada imbricades.
JavaScript promet
A JavaScript, es van introduir promeses a ES6. És un objecte amb un recobriment sintàctic. A causa del seu comportament asíncron, és una manera alternativa d'evitar escriure les devolucions de trucada per a operacions asíncrones. Avui en dia, les API web com fetch() s'implementen amb el prometedor, que proporciona una manera eficient d'accedir a les dades des del servidor. També va millorar la llegibilitat del codi i és una manera d'evitar escriure devolucions de trucada imbricades.
Les promeses a la vida real expressen confiança entre dues o més persones i una garantia que segurament passarà una cosa determinada. A JavaScript, una Promesa és un objecte que garanteix la producció d'un valor únic en el futur (quan sigui necessari). Promise en JavaScript s'utilitza per gestionar i abordar operacions asíncrones.
La Promesa retorna un objecte que assegura i representa la finalització o el fracàs de les operacions asíncrones i la seva sortida. És un proxy per a un valor sense conèixer la sortida exacta. És útil per a accions asíncrones per proporcionar un eventual valor d'èxit o motiu de fracàs. Així, els mètodes asíncrons retornen els valors com un mètode síncron.
En general, les promeses tenen els tres estats següents:
- Complet: l'estat complert és quan una acció aplicada s'ha resolt o completat amb èxit.
- Pendent: l'estat Pendent és quan la sol·licitud està en tràmit i l'acció aplicada no s'ha resolt ni rebutjat i encara es troba en el seu estat inicial.
- Rebutjat: l'estat rebutjat és quan l'acció aplicada ha estat rebutjada, provocant que l'operació desitjada falli. La causa del rebuig pot ser qualsevol cosa, inclòs l'error del servidor.
La sintaxi de les promeses:
let newPromise = new Promise(function(resolve, reject) { // asynchronous call is made //Resolve or reject the data });
A continuació es mostra un exemple d'escriptura de les promeses:
Aquest és un exemple d'escriure una promesa.
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))
A l'exemple anterior, podem veure com podem utilitzar de manera eficient les promeses per fer una sol·licitud des del servidor. Podem observar que la llegibilitat del codi augmenta en el codi anterior que en les devolucions de trucada. Les promeses proporcionen mètodes com .then() i .catch(), que ens permeten gestionar l'estat de l'operació en cas d'èxit o fracàs. Podem concretar els casos per als diferents estats de les promeses.
Async/Await en JavaScript
És una altra manera d'evitar l'ús de devolució de trucades imbricades. Async/Await ens permet utilitzar les promeses de manera molt més eficient. Podem evitar utilitzar l'encadenament del mètode .then() o .catch(). Aquests mètodes també depenen de les funcions de devolució de trucada.
Async/Await es pot utilitzar amb precisió amb Promise per millorar el rendiment de l'aplicació. Internament va resoldre les promeses i va proporcionar el resultat. A més, de nou, és més llegible que els mètodes () o catch().
No podem utilitzar Async/Await amb les funcions normals de devolució de trucada. Per utilitzar-lo, hem de fer que una funció sigui asíncrona escrivint una paraula clau asíncrona abans de la paraula clau de la funció. Tanmateix, internament també fa servir l'encadenament.
A continuació es mostra un exemple de 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();
Per utilitzar Async/Await, la funció s'ha d'especificar amb la paraula clau async, i la paraula clau await s'ha d'escriure dins de la funció. L'async aturarà la seva execució fins que la Promesa es resolgui o es rebutgi. Es reprendrà quan es faci la Promesa. Un cop resolt, el valor de l'expressió await s'emmagatzemarà a la variable que la conté.
Resum:
En poques paraules, podem evitar les devolucions de trucada imbricades utilitzant les promeses i async/wait. A part d'aquests, podem seguir altres enfocaments, com ara escriure comentaris i dividir el codi en components separats també pot ser útil. Però, avui dia, els desenvolupadors prefereixen l'ús de async/wait.
Conclusió:
L'infern de devolució de trucada a JavaScript es coneix com una situació en què s'està executant una quantitat excessiva de funcions de devolució de trucada imbricades. Redueix la llegibilitat i el manteniment del codi. La situació d'infern de devolució de trucada es produeix normalment quan es tracta d'operacions de sol·licituds asíncrones, com ara fer diverses sol·licituds d'API o gestionar esdeveniments amb dependències complexes.
Per entendre millor l'infern de devolució de trucada en JavaScript.
JavaScript ho considera tot com un objecte, com ara cadenes, matrius i funcions. Per tant, el concepte de devolució de trucada ens permet passar la funció com a argument a una altra funció. La funció de devolució de trucada completarà l'execució primer i la funció principal s'executarà més tard.
Les funcions de devolució de trucada s'executen de manera asíncrona i permeten que el codi continuï executant-se sense esperar a completar la tasca asíncrona.