Angular Basics Quelles sont les promesses Async / Attendez pourquoi vous vous en souciez

Le cœur du travail avec Angular, bien sûr, est d'avoir une bonne compréhension de JavaScript. JavaScript est un langage synchrone à thread unique qui exécute le code dans l'ordre défini. Il doit terminer le traitement d'une ligne de code avant de passer à la suivante.
Les navigateurs fournissent une API Web pour initialiser les requêtes asynchrones. Par exemple, si nous voulons envoyer une requête à un serveur, nous pouvons utiliser l'objet XMLHttpRequest ou Fetch API. Une fois qu'une demande asynchrone est terminée, nous devons gérer une réponse réussie ou échouée. Dans le passé, jQuery était largement utilisé pour faire des appels AJAX, je vais donc l'utiliser pour des exemples avec des rappels. Ci-dessous vous pouvez voir le code pour récupérer une liste de personnes à partir de l'API swapi
.
import $ from "jquery" ;
function ] onSuccess ( data textStatus jqXHR ) {
console . log ( "Personnes récupérées avec succès!" data ) ;
}
function onError ( jqXHR textStatus errorThrown ) {
console . error ( "Un problème est survenu lors de la récupération des données" ) ;
}
function onComplete ( jqXHR textStatus ) {
console . log ( "Request completed" ) ;
}
function get ( url ] onSuccess onError onComplete ) {
$ . ajax ( url {
méthode : "GET"
success : onSuccess
erreur : onError
terminé : onComplete
} ) ;
}
get ( "https://swapi.co/api/people" onSuccess onError onComplete ) ;
À l'époque, JavaScript n'avait pas autant de fonctionnalités qu'aujourd'hui, et les rappels étaient utilisés pour gérer les requêtes asynchrones . Malheureusement, l'utilisation de rappels a souvent conduit à un code difficilement maintenable et lisible, en particulier pour les opérations asynchrones plus complexes qui impliquaient de multiples demandes et transformations de données. Vous avez peut-être entendu un terme spécifique souvent associé à cette situation: un enfer de rappel.
Dans l'exemple ci-dessus, nous avons pas mal de code juste pour aller chercher une liste de personnes. Ajoutons un autre appel API et des gestionnaires pour cela et voyons à quel point il est lisible.
import $ from "jquery" ;
function onFetchPlanetsSuccess ( people ) {
return function ( data textStatus jqXHR ) [19659010] {
console . log ( "We got planets and people!" people data ) ; [19659072]} ;
}
function onFetchPlanetsError ( jqXHR textStatus ) {
console . error ( "Un problème est survenu lors de la récupération des planètes" ) ;
}
function onSuccess ( données textStatus jqXHR ) {
console . log ( "Personnes récupérées avec succès!" data ) ;
get (
" https://swapi.co/api/planets"[19659006letter,[19659098 OftenFetchPlanetsSuccess[19659006letter([19459003[19659006).
onFetchPlanetsError
) ;
}
function onError ( jqXHR textStatus errorThrown ) [19659010] {
console . error ( "Un problème est survenu lors de la récupération de personnes" ) ;
}
function onComplete ( jqXHR textStatus ) {
console . log ( "Request completed" ) ;
}
function get ( url ] onSuccess onError onComplete ) {
$ . ajax ( url {
méthode : "GET"
success : onSuccess
erreur : onError
terminé : onComplete
} ) ;
}
get ( "https://swapi.co/api/people" onSuccess onError onComplete ) ;
Plus il y a d'appels à faire, plus il devient laid et gênant de maintenir notre code. Il est également un peu plus difficile de suivre le flux d'exécution. Heureusement, ces jours sont derrière nous, car maintenant les actions asynchrones peuvent être gérées avec Promises et Async / Await.
Voyons d'abord ce que sont Promises .
Promises
Des promesses ont été ajoutées à JavaScript dans ES6, également connu sous le nom d'ECMAScript 2015. La raison en était de simplifier la gestion des requêtes asynchrones. Promise
est un proxy pour une valeur qui n'est pas encore connue au moment de la création de la promesse. Une promesse peut être dans trois états différents:
- En attente
- Accompli
- Rejeté
Voyons comment les promesses peuvent être utilisées:
function get ( url ]) {
retour nouveau Promesse ( ( résoudre rejeter ) => {
$ . ajax ( url {
méthode : "GET"
success : function ( data textStatus jqXHR ) {
resolution ( données ) ;
}
erreur : fonction ( jqXHR textStatus errorThrown ) {
rejeter ( errorThrown ) ;
}
} ) ;
} ) ;
}
get ( "https://swapi.co/api/people" )
. puis ( response => {
console . log ( "response" response ) ;
} )
. catch ( error => {
console . log ( "Un problème est survenu lors de l'extraction des données." ) ;
console . error ( error ) ;
} )
. enfin ( ([19659006]) => {
console . log ( 'request completed' )
} ) `` `
La méthode get
renvoie désormais une instance de l'objet Promise. Une promesse s'attend à recevoir une fonction en tant que paramètre, et elle passera résoudre
et rejeter
fonctions comme paramètres. Lorsqu'une promesse est initialisée, elle est dans l'état pending . La fonction résoudre
est appelée si une demande est exécutée avec succès et changerait l’état de la promesse en rempli . S'il y a un problème lors d'une requête, la fonction rejet
est appelée et l'état de la promesse passe à rejeté .
Pour obtenir une réponse de l'appel API lorsqu'il réussit , on peut enchaîner la méthode puis
; il recevra la réponse comme premier paramètre. Si une requête échoue, nous enchaînons la méthode catch
. Une autre méthode qui peut être chaînée est enfin
.
Vous trouverez ci-dessous un exemple avec l'API Fetch. Nous n'avons pas besoin d'utiliser new Promise ((résoudre, rejeter) => {})
car la méthode fetch
renvoie par défaut une promesse.
fetch ([19659013] "https://swapi.co/api/people" )
. puis ( response => {
return réponse . json () ;
} )
. then ( people = > {
return fetch ( 'https : / / swapi . co / api / planets ')
. puis ( response => response . json () )
. puis ( planets => {
return {
personnes
planètes
}
} )
} )
. puis ( ( { people ] planètes } ) => {
console . log ( 'result' people planets )
} )
. catch ( error => {
console . log ( "Un problème est survenu lors de l'extraction des données." ) ;
console . error ( error ) ;
} )
. enfin ( ([19659006]) => {
console . log ( 'request completed' )
} )
Maintenant nous avons moins de code, il est plus facile à suivre et plus propre que le exemple avec des rappels. Cependant, soyez prudent avec les promesses, car elles peuvent aussi rapidement devenir un gâchis impossible à tenir, surtout s'il y a beaucoup de promesses imbriquées. Par conséquent, essayez de les garder aussi peu profonds que possible et ne les imbriquez pas trop profondément.
Nous avons couvert les bases des promesses, alors voyons maintenant en quoi consiste Async / Await et comment il peut être utilisé pour améliorer notre gestion du code asynchrone.
Async / Await
Dans ECMAScript 2017, une nouvelle fonctionnalité pour gérer les requêtes asynchrones a été introduite: les fonctions async et le mot clé await. Async / Await fonctionne au-dessus des promesses et facilite la lecture et l'écriture du code asynchrone. Le code semble plus synchrone et, par conséquent, le flux et la logique sont plus compréhensibles. Surtout quand cela devient plus complexe et implique plus d'appels et de transformations.
Voici comment définir une fonction asynchrone:
async function fetchData () {[19659324]}
const fetchData = async () => {
}
La grande différence est juste un ajout du mot-clé async . Cependant, grâce à elle, nous pouvons maintenant attendre des promesses. Vous trouverez ci-dessous l'exemple précédent, mais maintenant réécrit avec async / await.
async function fetchData () {
try {[19659241] const peopleResponse = wait fetch ( "https://swapi.co/api/people" ) ;
const people = wait peopleResponse . json () ;
const planetsResponse = [19659038] attendre chercher ( "https://swapi.co/api/planets" ) ;
const planètes = attendre planetsResponse . json () ;
console . log ( "data" people planets ) ;
} catch ( error ) {
console . log ( "Un problème est survenu lors de l'extraction des données." ) ;
console . error ( error ) ;
} enfin {
console . log ( "Request completed" ) ;
}
}
fetchData ()) [19659006];
Il n'est pas nécessaire de chaîner des méthodes, car lorsque le moteur JavaScript atteint le mot-clé wait il ne passera pas à la ligne de code suivante tant que la promesse que nous attendons ne sera pas résolue. Nous n'utilisons plus le chaînage puis
et catch
et, par conséquent, pour gérer les erreurs, nous devons utiliser try / catch.
Nous avons réussi à réduire la quantité de code requise pour récupérer énormément de données. Le code est beaucoup plus facile à maintenir et semble plus synchrone donc il est plus facile de raisonner.
Top-level Await
Le mot-clé await ne peut être utilisé qu'à l'intérieur d'un async fonction. Sinon, une erreur sera générée. Cependant, au moment de la rédaction de cet article, il existe une proposition d'attente de premier niveau qui est actuellement à l'étape 3. Elle permettrait d'utiliser await en dehors d'une asynchrone. fonction. Vous pouvez en savoir plus ici: https://github.com/tc39/proposal-top-level-await .
Async / Await + Promise.all ()
Notre exemple précédent avec async / await est bien meilleur que les tentatives précédentes avec des rappels et des promesses, mais il y a une amélioration que nous pouvons faire. Nous effectuons deux appels API: un pour récupérer des personnes et un pour récupérer des planètes. Cependant, avant que le dernier appel d'API puisse être effectué, le premier doit se terminer en premier. Cela est dû au fonctionnement d’async / await et c’est une perte de temps si le deuxième appel d’API ne repose en aucune façon sur le premier.
Par conséquent, faisons exécuter les deux appels en parallèle. Nous pouvons utiliser Promise.all
pour cela.
async function fetchData () {
try {
const fetchPeoplePromise = fetch ( "https://swapi.co/api/people" ) . puis ( response => response . json () ) ;
const fetchPlanetsPromise = [19659008] fetch ( "https://swapi.co/api/planets" ) . puis ( response => réponse . json () ) ;
const [ people planets ] [19659157] = attendre Promise . all ( [ fetchPeoplePromise fetchPlanetsPromise ] )
console . log ( "data" people planets ) ;
} catch ( error ) {
console . log ( "Un problème est survenu lors de l'extraction des données." ) ;
console . error ( error ) ;
} enfin {
console . log ( "Request completed" ) ;
}
}
Les deux requêtes sont initialisées dès que possible. Comme nous n'avons utilisé le mot clé await sur aucune des requêtes d'extraction, le moteur JavaScript continuera à exécuter le code jusqu'à ce qu'il atteigne la ligne await Promise.all . Promise.all attendra que toutes les promesses passées dans un tableau soient remplies. Si l'une des promesses est rejetée, alors une erreur sera lancée, et elle sera traitée dans le bloc catch .
Personnellement, j'utilise async / await sur des promesses pures chaque fois que je le peux. Cependant, écrire try / catch tout le temps peut être assez fastidieux. Voici donc un petit extrait de code qui peut être utilisé pour vous aider:
const withAsync = async fn => {
try [19659010] {
const response = wait fn ()
return [ response null ]
} catch ( error ) {
return [ null error ]
}
}
const [ people error ] = wait withAsync ( () => fetch ( "https://swapi.co/api/people" ) . puis ( response => response . json () )
if ( error ) {
console . error ( error )
return
}
console . log ( 'we have people!' people )
Il n'est pas nécessaire d'écrire try / catch tout le temps. Au lieu de cela, il est encapsulé dans la fonction withAsync . S'il y a une erreur, nous pouvons la gérer et renflouer, et si tout va bien, nous pouvons gérer la réponse.
Conclusion
Nous avons expliqué comment les actions asynchrones en JavaScript peuvent être gérées avec des rappels, des promesses et une asynchrone. /attendre. Ce sont des fonctionnalités clés pour JavaScript et Angular. Les exemples de code montrent clairement à quel point il était difficile dans le passé de gérer les appels d'API. Au moins maintenant, si vous devez travailler avec un ancien projet, vous savez peut-être par où commencer et comment convertir un code plus ancien pour utiliser une approche plus moderne.
Source link