Promise, Async & Await

Ce tutoriel est déprécié ! Un tutoriel plus récent est maintenant disponible : Promise.
Voir la vidéo
Description Sommaire
Ce tutoriel est déprécié ! Un tutoriel plus récent est maintenant disponible : Promise.

La nature asynchrone du JavaScript pose souvent des problèmes en terme d'organisation. Si on vient d'un langage plus classique il est parfois difficile de concevoir des fonctions avec une résolution asynchrone. Comment renvoyer les résultats quand le code n'est pas éxécuté de manière synchrone ?

00:00 - Les callbacks
08:52 - Les promesses
20:25 - Async & Await

Les callbacks

Nous souhaitons donc créer une fonction pour faire un appel Ajax. La résolution de la requête Ajax se fait de manière asynchrone et il n'est donc pas possible d'utiliser un simple return.

var ajax = function (url) {
  var req = new XMLHttpRequest()
  req.open('GET', url, true)
  req.onreadystatechange = function (aEvt) {
    if (req.readyState == 4) {
       if(req.status == 200)
         // return req.responseText n'est pas possible
         // On ne peut pas utiliser de "return" ici car on est dans la fonction 
         // onReadyStateChange
       else
         // ...
    }
  };
  req.send(null)
}

ajax('https://jsonplaceholder.typicode.com/users') 
// Comment détecter la fin de la requête ajax ?

Il faut donc être capable de détecter la résolution de la requête afin d'effectuer la suite de nos traitements. La solution pour remédier cette problématique est d'utiliser des fonctions anonymes que l'on va éxécuter lors de la résolution de notre code. Ces fonctions sont appellées callbacks.

var ajax = function (url, success, error) {
  var req = new XMLHttpRequest()
  req.open('GET', url, true)
  req.onreadystatechange = function (aEvt) {
    if (req.readyState == 4) {
       if(req.status == 200)
         success(req.responseText)
       else
         error(req)
    }
  };
  req.send(null)
}

ajax('https://jsonplaceholder.typicode.com/users', function (response) {
  // response contient le code HTML de notre page, on peut faire le reste du traitement
}, function (req) {
  // Le serveur n'a pas répondu comme attendu
})

Cette méthode fonctionne mais si vous souhaitez effectuer des opérations asynchrones en cascade votre code va vite ressembler à ça...

ajax('https://jsonplaceholder.typicode.com/users', function (response) {
  ajax('https://jsonplaceholder.typicode.com/posts', function (response) {
    ajax('https://jsonplaceholder.typicode.com/tutoriels', function (response) {
      // Là j'ai tout !
    }, function (req) { })
  }, function (req) { })
}, function (req) { })

Et c'est encore pire quand on veut tout faire en même temps...

Les promesses

Les promesses permettent une approche différente du problème et sont apparues avec l'ES2015.

let ajax = function (url) {
  // On renvoie une promesse qui prend en paramettre une fonction 
  // avec 2 paramètres, le callback de succès et d'erreur
  return new Promise(function (resolve, reject) {
    // Le reste du code ressemble à la méthode précédente
    let req = new XMLHttpRequest()
    req.open('GET', url, true)
    req.onreadystatechange = function (aEvt) {
      if (req.readyState == 4) {
         if(req.status == 200)
           resolve(req.responseText)
         else
           reject(req)
      }
    };
    req.send(null)
  })
}

// L'appel à la fonction peut se faire de cette manière là
ajax('https://jsonplaceholder.typicode.com/users')
.then(function (response) {
  // Le serveur a correctement répondu
}).catch(function (req) {
  // Le serveur n'a pas répondu comme attendu
})

A vu de nez cette méthode semble proche de la méthode précédente. Cependant, les promesses peuvent être enchainées ce qui simplifie grandement la gestion en cascades et en parallèle.

// Cascade
ajax('https://jsonplaceholder.typicode.com/users')
.then(function (response) {
  // Si le then retourne une promesse on peut enchainer
  return ajax('https://jsonplaceholder.typicode.com/posts')
})
.then(function (response) {
  // Si le then retourne une promesse on peut enchainer
  return ajax('https://jsonplaceholder.typicode.com/comments')
})
.then(function (response) {
  // La série d'opération est finie
})
.catch(function (req) {
  // Une des requête a échouée
})

// En parallèle
Promise.all([
  ajax('https://jsonplaceholder.typicode.com/users'),
  ajax('https://jsonplaceholder.typicode.com/posts'),
  ajax('https://jsonplaceholder.typicode.com/comments')
]).then(function (responses) {
  responses // [response1, response2, response3]
}).catch(function (errors) { })

Async & Await

L'ES2017 propose en draft une amélioration du système de promesses avec la création de fonction asynchrones.

// Une fonction qui renvoie une promesse peut être marqué comme "async"
// Elle peut alors attendre la résolution d'une autre promesse avec "await"
let getPost = async function () {
  // Plutot que d'utilise le then on peut attendre la résolution
  let response = await ajax('https://jsonplaceholder.typicode.com/posts')
  // Return permettra le resolve de la promesse
  return JSON.parse(response) 
  // Un throw permettra de reject la promesse
}

// Cette fonction s'utilise comme précédemment
getPost().then(posts => {
  console.log(posts)
}).catch(error => { })
Publié
Technologies utilisées
Auteur :
Grafikart
Partager