Async & Await

4

Nous avons vu précédemment comment récupérer des informations sur un serveur distant grâce à fetch().

Par exemple, pour récupérer les informations d'une personne fictive, il est possible d'effectuer un appel à l'API de randomuser.me/api

fetch("https://randomuser.me/api?results=1")
  .then(response => response.json())
  .then(data => console.log(data));

Ce code affiche dans la console un objet contenant les différentes informations d'une personne fictive:

{
  gender: "female",
  name: {
    first: "Eléonore",
    last: "Gonzalez",
    title: "Ms",
  },
  nat: "FR"
}

Imaginons que des informations supplémentaires sur le pays (FR 🇫🇷) de cette personne soient demandés. Un appel à un deuxième API restcountries.eu spécifiant le pays désiré serait requis afin d'obtenir ces informations.

Le code ressemblerait alors à ceci:

function getPeople() { 
  fetch("https://randomuser.me/api?results=1")
    .then(responseUser => responseUser.json())
    .then(dataUser => {
      const user = dataUser.results[0];
        
      fetch(`https://restcountries.eu/rest/v2/alpha/${user.nat}`)
        .then(responseCountry => responseCountry.json())
        .then(dataCountry => {
          console.log({
            user: user,
            country: dataCountry
          });
        });
    });
}

getPeople();

Ce code n'est pas mauvais. Il fonctionne, mais certains éléments donnent envie de grincer des dents.

Remarquez comment les .then() sont imbriqués les uns à la suite des autres. Imaginez qu'avec les informations du pays, vous deviez appeler un autre API supplémentaire et ainsi de suite, vous, vous retrouveriez avec ce que l'on appelle un callback hell 👿, soit plusieurs callbacks imbriqués les uns dans les autres, rendant la lecture du code et le débogage ardu.

Voici le résultat obtenu dans la console:

{
  user: {
    gender: "female",
    name: {
      first: "Eléonore",
      last: "Gonzalez",
      title: "Ms",
    },
    nat: "FR"
  },
  country: {
    capital: "Paris",
    name: "France",
    population: 66710000,
    region: "Europe"
  }
}

Async et Await à la rescousse

Il est heureusement possible de rendre ce code plus lisible et plus facilement déboguable.

Pour ce faire, une fonction doit retournee un résultat de façon asynchrone, bref que son return soit une promesse (promise) et non une valeur directement.

Le mot-clé async préfixant une fonction permet d'effectuer cette conversion. Par exemple, une fonction synchrone de base ressemble à ceci:

function demo() {
  return "Résultat";
}

console.log(demo());
// Résultat

Pour la convertir en fonction asynchrone, il suffit de la préfixer avec async:

async function demo() {
  return "Résultat";
}

console.log(demo());
// [object Promise] {}

Remarquez que le retour est une promesse et non une valeur directement.

Pour accéder à la valeur dans la promesse (promise), il faut attendre que celle-ci soit complétée. À ce moment, la méthode .then() est invoquée et la valeur associée à la fonction lui est passée en paramètre, il est donc finalement possible d'y accéder.

async function demo() {
  return "Résultat";
}

demo() // 👈 retourne une promesse
  .then(data => { // promesse ✅, voici sont contenu
    console.log(data) // affiche le contenu de la promesse
  });
// Résultat

Pour en savoir plus, voir cet article de MDN🦖 à propos de async.

Contrairement à une fonction synchrone de base, qui tente de répondre immédiatement, cette fonction asynchrone retourne maintenant une promesse (promise) de répondre prochainement.

Elle peut donc se permettre d'attendre le résultat d'un .fetch() grâce à await avant de répondre.

Dans l'exemple de l'usager fictif, d'on la nationalité est utilisée en deuxième temps pour allez récupérer des informations supplémentaires sur son pays, pourrait donc être refait ainsi avec async et await:

async function getPeople() { 
  const user = await getUser();
  const country = await getCountry(user.nat);

  return {
    user,
    country
  }
}

function getUser() {
  return fetch("https://randomuser.me/api?results=1")
    .then(response => response.json())
    .then(data => data.results[0]);
};

function getCountry(country) {
  return fetch(`https://restcountries.eu/rest/v2/alpha/${country}`)
    .then(response => response.json())
    .then(data => data);
};

getPeople()
  .then(data => {
    console.log(data);
  });

Gardez à l'esprit que await ne peut être utilisé uniquement qu'à l'intérieur d'une fonction async.

Pour en savoir plus, voir cet article de MDN🦖 sur await

Donnez votre opinion
sur les notes de cours sur cette page.
Merci d'avoir partagé ton opinion 😎
Pssst, c'est 💯 anonyme