Retour au blog
mai 2018·5 min de lectureTraduit par IA
Langue:DeutschEnglishFrançaisÖsterreichischKlingonian Version originale: Deutsch

Promises JavaScript

#development#javascript#programmierung#promise

Depuis juin 2015, les Promises sont arrivées aussi en JavaScript avec ES6 et peuvent y être utilisées nativement. Peut-être que certains d'entre vous sont comme moi au début et ne savent pas trop à quoi servent les promises ni comment les utiliser.

Que sont les Promises ?

JavaScript est « monothread » et travaille donc de façon séquentielle, c'est-à-dire synchrone. Les Promises exécutent, en bref, plusieurs fonctions les unes après les autres, plus précisément : nous pouvons appeler la fonction 2 exactement quand la fonction 1 est terminée. Nous pouvons donc d'abord exécuter une action et ne démarrer l'action suivante qu'une fois celle-ci terminée. C'est utile par exemple pour une requête Ajax : si nous ne voulons démarrer le traitement des données qu'une fois la requête Ajax terminée, nous pouvons utiliser une Promise, qui distingue en outre si la Promise a réussi ou a provoqué une erreur. Sans Promise, JavaScript continuerait même si la requête Ajax n'est pas terminée, avec pour résultat que la valeur de retour peut encore être vide. Les Promises ne sont donc utiles que pour les activités asynchrones : pour les activités synchrones, nous pouvons nous fier au traitement séquentiel de JavaScript. Le code synchrone est très simple : il s'exécute de haut en bas et l'étape 2 attend toujours que l'étape 1 soit terminée. Nous devons donc toujours attendre qu'une action soit terminée pour en exécuter une suivante, ce qui est pénible et prend surtout du temps, avec pour conséquence que le script met d'autant plus longtemps à finir. Pire encore : si nous ne plaçons pas le code JavaScript à la fin de la page, l'exécution du JavaScript entre en concurrence avec le rendu de la page (JavaScript, CSS, HTML, etc. partagent le même thread : l'exécution d'un script bloque donc la poursuite de la construction de la page web), et la page se construit donc lentement. Cela agace l'utilisateur final, et les utilisateurs finaux agacés agacent le développeur.

États

La Promise peut avoir 4 états :

  • Pending : la Promise en est encore à la partie 1 : elle n'a donc jusqu'ici ni réussi ni échoué
  • Fulfilled : opération terminée -> démarrer la fonction Fulfilled
  • Rejected : une erreur est survenue -> exécuter la fonction Rejected
  • Settled : la Promise est terminée et soit rejected, soit fulfilled

Pourquoi pas if et if et if et if… ?

Nous pouvons évidemment aussi imbriquer le code dans un tas de tests IF et obtenir la fameuse pyramide de l'enfer (pyramid of doom). Avec les Promises, nous pouvons l'éviter.

Syntaxe

La syntaxe d'une Promise ressemble à new Promise(function(resolve, reject) { / CODE / });. Dans le code, les fonctions / arguments resolve() (conduit à l'état « fulfilled » et est appelé quand le code ne renvoie pas d'erreur / que la Promise a réussi) et reject() (conduit à l'état « rejected » et est appelé quand le code présente une erreur / que la Promise n'a pas réussi) peuvent maintenant être appelés.

Les bases

Un court exemple serait donc :

var promise = new Promise(function(resolve, reject) {
  // Hier deinen Code einsetzen, der bei Erfolg success = true setzt
  success === true ? resolve('Gut') : reject('Schlecht');
});
promise.then(function(result) {
  console.log("Erfolg:");
  console.log(result);
}, function(result) {
  console.log("Fehler:");
  console.log(result);
});

Tant que votre code s'exécute, la Promise est à l'état « Pending » ; dès qu'il est terminé, elle est à l'état « Settled », soit Fulfilled (si success === true) et resolve() est appelé, soit Rejected (si success === false) et reject() est appelé. Le constructeur de Promise reçoit donc un callback avec deux paramètres : Resolve (action terminée avec succès) et Reject (une erreur est survenue). Dès que le code est terminé (promise.then()), selon que resolve() ou reject() est appelé, « Erfolg: Gut » ou « Fehler: Schlecht » est affiché. En clair : la variable promise contient la Promise. Promise.then() reçoit en paramètres les deux fonctions que nous avons définies dans « new Promise » : cela correspond à peu près à promise.then(function resolve(result){}, function reject(result){});. L'avantage est que resolve() et reject() ne sont appelés qu'une fois le code de la Promise exécuté. C'est utile surtout pour les requêtes Ajax asynchrones : nous ne traitons les données de la requête qu'une fois la requête terminée.

Exemple de code asynchrone

Comme base de tous les exemples suivants, nous prenons cette requête AJAX asynchrone.

function GET(target) {
  return new Promise(function(success, error) {
    var request = new XMLHttpRequest();
    request.open("GET", target);
    request.addEventListener("load", function() {
      if (this.status == 200) {
        success('Erfolgreich!');
      } else {
        error(this.status);
      }
    }, false);
    request.send(target);
  });
}

Promising the promise

Pour que la confusion soit parfaite, resolve() et reject() renvoient à leur tour une Promise : nous pouvons donc accrocher et chaîner plusieurs Promises.

GET("file1.html")
  .then(GET("file2.html"))
  .then(GET("file3.html"));

Nous chargeons donc d'abord file1.html, puis file2.html, puis file3.html. La fonction « success » ne fait rien d'autre que de créer à nouveau une Promise, mais avec un autre fichier.

Promise : It will be an array

Il n'est pas nécessaire d'accrocher plusieurs Promises identiques pour les chaîner. Pour cela, il y a la méthode all() : elle accepte plusieurs objets Promise sous forme de tableau et exécute toutes les fonctions de ce tableau comme une Promise. Petit exemple :

Promise.all([GET("file1.html"), GET("file2.htlm")]).then(
  function (success) {
    console.log(success);
  },
  function (error) {
    console.log("Es trat ein Fehler auf:");
    console.log(error);
  }
);

Toutes les fonctions contenues dans le tableau sont maintenant transmises à la Promise. Dès qu'une erreur survient, error() est appelé, et success() n'est appelé qu'une fois toutes les fonctions exécutées avec succès. Nous pouvons aussi utiliser catch : .catch(function(error) {}); Notre exemple ressemblerait alors à ceci :

Promise.all([GET("file1.html"), GET("file2.htlm")]).then(
  function(success) {
    console.log(success);
  }).catch(
  function(error) {
    console.error(error);
  });

La Promise la plus rapide

Promise.race() ne renvoie qu'une seule Promise : celle qui s'est terminée en premier.

Promise.race([GET("smallfile.jpg"), GET("bigfile.jpg"), GET("extrasmallfile.jpg")]).then(
  function (success) {
    console.log(success);
  }
);

Supposons que smallfile fasse 200 Mo, extrasmallfile 2 Ko et bigfile 3 Go. Dans ce cas, success() est appelé, et ce après l'appel du fichier extrasmallfile. Comme les trois appels de fonction s'exécutent de manière asynchrone, bigfile n'a pas non plus besoin d'attendre smallfile, ni extrasmallfile d'attendre bigfile.

Plus récentMéthodes de protection contre le SPAM n° 1 : le honeypotPlus ancienÉviter le SPAM avec qmail