Com evitar l'infern de devolució de trucada a Node.js

Bloc

Com evitar l'infern de devolució de trucada a Node.js

Com evitar l'infern de devolució de trucada a Node.js

Infern de devolució de trucada és un fenomen que afecta un desenvolupador de JavaScript quan intenta executar diverses operacions asíncrones una després de l'altra. Algunes persones en diuen que és el piràmide de la fatalitat .

Vegem un exemple del que anomenem infern de devolució de trucada.

doSomething(param1, param2, function(err, paramx){ doMore(paramx, function(err, result){ insertRow(result, function(err){ yetAnotherOperation(someparameter, function(s){ somethingElse(function(x){ }); }); }); }); });

Nota- El codi anterior és per a demostracions i no per a un codi de treball.

Això es veu malament només des del propi esquelet. En codi real, evidentment, tindreu altres afirmacions com if, for o alguna altra operació juntament amb aquestes funcions imbricades. Afegiu-los al codi anterior i quedaria realment desordenat i inmanejable.

Actualització: s'ha afegit l'increïble async-await després del llançament a Node.js 7.10.0

Consell Pro

No sobrecarregueu les funcions. La majoria de les vegades és possible que el veritable problema al qual us trobeu no sigui infern de devolució de trucada , més aviat, són funcions mal escrites. En aquests casos, les solucions que veurem a continuació estructurarien el vostre codi, però no solucionaran el vostre problema real. Per tant, per regla general, feu que la vostra funció faci menys, és a dir, escriviu petites funcions que realitzin una sola tasca.

Tècniques per evitar l'infern de devolució de trucada

Hi ha diverses tècniques per tractar l'infern de devolució de trucada. En aquest tutorial, farem una ullada als dos següents, en particular.

  1. Utilitzant Async.js

  2. Ús de promeses

  3. Utilitzant Async-Await

Gestió de devolucions de trucada mitjançant Async.js

Asíncron és un mòdul npm realment potent per gestionar la naturalesa asíncrona de JavaScript. Juntament amb Node.js, també funciona per a JavaScript escrit per a navegadors.

Async proporciona moltes utilitats potents per treballar amb processos asíncrons en diferents escenaris.

substituir diversos caràcters python

Instal·lació

npm install --save async

async.waterfall ()
Per al nostre problema, analitzarem dues funcions de l’asincronia en particular. és a dir async.waterfall`) i async.series().
Async Waterfall és útil quan voleu executar algunes tasques una després de l'altra i, alhora, transmetre el resultat de la tasca anterior a la següent.

async.waterfall() inclou una sèrie de funcions ‘tasks‘ i una final ‘callback‘ funció que es diu després de totes les funcions de tasks ha completat o un callback es diu amb un error.
Feu un cop d'ull a continuació per obtenir una millor comprensió.

CASCADA ASYNC

var async = require('async'); async.waterfall([ function(callback) { //doSomething callback(null, paramx); //paramx will be availaible as the first parameter to the next function /** The 1st parameter passed in callback. @null or @undefined or @false control moves to the next function in the array if @true or @string the control is immedeatly moved to the final callback fucntion rest of the functions in the array would not be executed */ }, function(arg1, callback) { //doSomething else // arg1 now equals paramx callback(null, result); }, function(arg1, callback) { //do More // arg1 now equals 'result' callback(null, 'done'); }, function(arg1, callback) { //even more // arg1 now equals 'done' callback(null, 'done'); } ], function (err, result) { //final callback function //finally do something when all function are done. // result now equals 'done' });

Per tant, utilitzant async.waterfall(), escriviríeu codi verticalment en lloc de sagnar-lo horitzontalment i entrar a la piràmide de la desgràcia. A més, el vostre codi seria molt més organitzat i fàcil de llegir.

async.series ()
Async proporciona una altra funció per gestionar l'execució en sèrie, async.series(). La sèrie Async funciona de manera similar a la cascada d'Async, executant funcions a la matriu una darrere l'altra amb la diferència que no passarà les dades d'una funció a una altra, en lloc que totes les funcions hagin finalitzat la seva execució, el resultat de les funcions estaran disponibles a la devolució de trucada final com a matriu. Similar a async.waterfall() a async.series() a més, quan es crida a qualsevol de les funcions amb una devolució de trucada d'error, no s'executen més funcions a la matriu i es crida immediatament a la devolució de trucada final amb el valor de l'error. Feu un cop d'ull a continuació per obtenir una imatge clara.

SÈRIE ASYNC

var async = require('async'); async.series([ function(callback){ // do some stuff ... callback(null, 'one'); /** The 1st parameter passed in callback. @null or @undefined or @false control moves to the next function in the array if @true or @string the control is immedeatly moved to the final callback fucntion with the value of err same as passed over here and rest of the functions in the array would not be executed */ }, function(callback){ // do some more stuff ... callback(null, 'two'); } ], // optional callback function(err, results){ // results is now equal to ['one', 'two'] });

Hi ha més funcions interessants disponibles amb el mòdul asincronitzat. Assegureu-vos de comprovar-les i utilitzar-les als vostres projectes Node.js.
Visiteu la pàgina de Github aquí: Async.js Github

Gestionar l'infern de devolucions de trucada mitjançant promeses

Les promeses són alternatives a les devolucions de trucada quan es tracta de codi asíncron. Les promeses retornen el valor del resultat o una excepció d'error. El nucli de les promeses és el .then() funció, que espera que es retorni l'objecte promesa. El .then() La funció pren com a arguments dues funcions opcionals i, segons l'estat de la promesa, només se'n cridarà una. La primera funció es diu quan es compleix la promesa (un resultat reeixit). La segona funció s’anomena quan es rebutja la promesa.
Vegem l'estructura d'una promesa típica.

PROMESES

var outputPromise = getInputPromise().then(function (input) { //handle success }, function (error) { //handle error });

Encadenar promeses

També podem encadenar promeses, aquesta és una alternativa equivalent a la devolució de trucades. Hi ha dues maneres d’encadenar les promeses. Les promeses es poden encadenar dins o fora dels controladors (funció .then ()). Encadenar les promeses fora del controlador és molt net i fàcil de llegir, però és possible que haguem de encadenar les promeses dins del controlador si volem utilitzar algun paràmetre del nostre següent controlador que estigui disponible a l’abast del controlador anterior. Tot i que massa encadenament dins del controlador tornarà a donar lloc a un codi horitzontal que estem intentant evitar. També podem encadenar promeses amb una combinació de cadenes interiors i exteriors. Com a norma general, us recomanaria que eviteu encadenar dins del controlador.

A més, una altra bona part de les cadenes de promeses és que també podem afegir un bloc de captures al final de la cadena per detectar qualsevol error que es produeixi en alguna de les funcions about.

ENCADENAMENT DE PROMESSES

return getUsername().then(function (username) { return getUser(username); }) .then(function (user) { //example of chaining outside the handler return userPassword().then(function(password){ /** example of chaining inside the handler, since we need to use the @user param from the previous handler scope */ if(user.password !== password){ //reject promise or throw error return; } }); }) .catch(function(e){ //handle error console.log(e); });

Crear una funció que retorni un Promise
Per crear una funció que funcioni amb promeses, podem utilitzar la classe Promise integrada.

http //fxnetworks.com/activate xboxone
const test = function(){ return new Promise((resolve, reject)=>{ setTimeout(() => { resolve('done'); }, 10); }); } //call it like this test().then((resp)=>{ console.log(resp); }) .catch((e)=>{ console.log(e); });

Una promesa es considera satisfactòria si el valor es torna amb el resolve i no té èxit si es retorna amb el reject mètode.

Canviar les devolucions de trucada a promeses

Hi ha algunes bones biblioteques per a promeses, veurem els exemples dels populars Q de Kriskowal promet biblioteca. Assegureu-vos que teniu q instal·lat.

npm install --save q

RECLAMACIONS A LES PROMESSES

var fs = require('fs'); var Q = require('q'); var readFile = Q.nfbind(fs.readFile); readFile('foo.txt', 'utf-8').then(function (text) { //handle success }, function(err){ //handle error });

Utilitzant Async Await

Una de les millors coses que apareixerà recentment a Node.js és la funció d'espera asíncron. Async await fa que el codi asíncron sembli síncron. Això només ha estat possible a causa de la reintroducció de promeses a node.js. Async-Await només funciona amb funcions que retornen una promesa.

Ara mateix, la millor manera d’evitar l’infern de devolució de trucada és mitjançant async-await a Node.js. Ho entenem amb un exemple.

ASYNC-AWAIT

const getrandomnumber = function(){ return new Promise((resolve, reject)=>{ setTimeout(() => { resolve(Math.floor(Math.random() * 20)); }, 1000); }); } const addRandomNumber = async function(){ const sum = await getrandomnumber() + await getrandomnumber(); console.log(sum); } addRandomNumber();

Si veieu més amunt, tenim una funció que ens retorna un número aleatori després d'1 segon. Aquesta funció retorna una promesa. Utilitzant el await paraula clau li diem a javascript que esperi el resultat abans de seguir endavant. Però això await la paraula clau només funciona dins de funcions declarades com async. Quan declarem una funció com async, estem dient a javascript que suspengui l'execució fins que arribi el resultat sempre que es trobi amb el await paraula clau.

Ara, en les promeses de manejar els errors, podríem encadenar directament un bloc de captures. Com ho faríeu en el cas anterior? Bé, simplement podem utilitzar un try-catch bloc.
Així doncs, el nostre exemple anterior es veurà així ...

ASYNC-AWAIT

const getrandomnumber = function(){ return new Promise((resolve, reject)=>{ setTimeout(() => { resolve(Math.floor(Math.random() * 20)); }, 1000); }); } const addRandomNumber = async function(){ try { const sum = await getrandomnumber() + await getrandomnumber(); console.log(sum); } catch (error) { //handle error console.log(error); } } addRandomNumber();

Una cosa més important a tenir en compte és, sempre que declareu una funció com async aquesta funció retornarà un Promise

Conclusió

Hem vist com podem fer front al problema de l'infern de devolució de trucada a Node.js. Hi ha algunes maneres més de solucionar el problema, com l'ús de generadors, la modularització, etc. Però ho sentim biblioteca asíncron i les promeses són les dues solucions de facto per fer front a l'infern de devolució de trucada. Però això només va ser fins a l'arribada de async-await. Amb async-await aquí hauríeu de començar a utilitzar-lo immediatament als vostres programes per netejar i organitzar el vostre codi. Tanmateix, recordeu el que hem comentat anteriorment, el vostre problema principal potser no sigui l'infern de devolució de trucada, sinó que podria ser funcions mal escrites. Assegureu-vos de mantenir les funcions primes i centrades en una sola tasca. Aprendreu més informació sobre l'asincronia i prometreu només quan els feu servir. Assegureu-vos de provar-los la propera vegada en els vostres projectes.

Gràcies per llegir!

#node #nodejs #javascript