L'objet Promise (pour « promesse ») est utilisé pour réaliser des traitements de façon asynchrone. Une promesse représente une unique opération asynchrone qui n'a pas encore été complétée, mais qui est attendue dans le futur.

Syntaxe

new Promise( /* exécuteur */ function(resolve, reject) { ... } );

Paramètres

exécuteur
Un objet fonction qui prend deux arguments : resolve et reject. Cette fonction est exécutée immédiatement par l'implémentation de Promise qui fournit les fonctions resolve et reject (elle est exécutée avant que le constructeur Promise ait renvoyé l'objet créé). Les fonctions resolve et reject sont liées à la promesse et appeler l'une ou l'autre change respectivement l'état de la promesse en tenue si tout c'est bien passé ou en rompue si une erreur à eu lieu. On attend de l'exécuteur qu'il démarre un travail asynchrone puis, une fois le travail terminé, appelle la fonction resolve ou la fonction reject pour définir l'état final de la promesse.

Description

L'interface Promise représente un intermédiaire (proxy) vers une valeur qui n'est pas nécessairement connue au moment de sa création. Cela permet d'associer des gestionnaires au succès éventuel d'une action asynchrone et à la raison d'une erreur. Ainsi, des méthodes asynchrones renvoient des valeurs comme les méthodes synchrones, la seule différence est que la valeur retournée par la méthode asynchrone est une promesse (d'avoir une valeur plus tard).

Une Promise est dans un de ces états :

  • pending (en attente) : état initial, la promesse n'est ni remplie, ni rompue ;
  • fulfilled (tenue) : l'opération a réussi ;
  • rejected (rompue) : l'opération a échoué ;
  • settled (acquitée) : la promesse est tenue ou rompue mais elle n'est plus en attente.

Une promesse en attente peut être tenue avec une valeur ou rompue avec une raison (erreur). Quand on arrive à l'une des deux situations, les gestionnaires associés lors de l'appel de la méthode then sont alors appelés. (Si la promesse a déjà été tenue ou rompue lorsque le gestionnaire est attaché à la promesse, le gestionnaire est appelé. Cela permet qu'il n'y ait pas de situation de compétition entre une opération asynchrone en cours et les gestionnaires ajoutés).

Les méthodes Promise.prototype.then() et Promise.prototype.catch() renvoient des promesses et peuvent ainsi être chaînées. C'est ce qu'on appelle une composition.

Note: Une promesse est dans l'état settled (acquittée) qu'elle soit tenue ou rompue mais plus en attente. Le terme resolved (résolue) est aussi utilisé concernant les promesses — cela signifie que la promesse est acquittée ou bien enfermée dans une chaine de promesse. Le billet de Domenic Denicola, States and fates (en anglais), contient de plus amples détails sur la terminologie utilisée.

Attention : D'autres langages utilisent des mécanismes d'évaluation à la volée (lazy evaluation) et de déport des calculs (deferring computations). Ces mécanismes sont également intitulés promesses (promises). En JavaScript, les promesses correspondent à des processus déjà lancés et qui peuvent être chaînés avec des fonctions de retour. Si vous cherchez à retarder l'évaluation, vous pouvez utiliser les fonctions fléchées sans arguments (ex. f = () => expression) afin de créer une expression à évaluer plus tard et utiliser f() pour l'évaluer au moment voulu.

Propriétés

Promise.length
Une propriété de longueur qui vaut 1 (le nombre d'arguments pour le constructeur).
Promise.prototype
Cette propriété représente le prototype du constructeur Promise.

Méthodes

Promise.all(itérable)
Renvoie une promesse tenue lorsque toutes les promesses de l'argument itérable sont tenues ou bien une promesse rompue dès qu'une promesse de l'argument itérable est rompue. Si la promesse est tenue, elle est résolue avec un tableau contenant les valeurs de résolution des différentes promesses contenues dans l'itérable (dans le même ordre que celui-ci). Si la promesse est rompue, elle contient la raison de la rupture de la part de la promesse en cause, contenue dans l'itérable. Cette méthode est utile pour agréger les résultats de plusieurs promesses tous ensemble.
Promise.race(itérable)
Renvoie une promesse qui est tenue ou rompue dès que l'une des promesses de l'itérable est tenue ou rompue avec la valeur ou la raison correspondante.
Promise.reject(raison)
Renvoie un objet Promise qui est rompue avec la raison donnée.
Promise.resolve(valeur)
Renvoie un objet Promise qui est tenue (résolue) avec la valeur donnée. Si la valeur possède une méthode then, la promesse renvoyée « suivra » cette méthode pour arriver dans son état, sinon la promesse renvoyée sera tenue avec la valeur fournie. Généralement, quand on veut savoir si une valeur est une promesse, on utilisera Promise.resolve(valeur) et on travaillera avec la valeur de retour en tant que promesse.

Promise prototype

Propriétés

Promise.prototype.constructor
Renvoie la fonction qui a créé le prototype d'une instance. Ce sera la fonction Promise par défaut.

Méthodes

Promise.prototype.catch(onRejected)
Ajoute une fonction callback à utiliser en cas de rejet de la promesse. Elle renvoie une nouvelle promesse qui est résolue avec la valeur de retour du callback s'il est appelé ou avec la valeur de résolution initiale si la promesse est tenue (et non rejetée).
Promise.prototype.then(onFulfilled, onRejected)
Ajoute des fonctions à utiliser en cas de résolution ou de rejet de la promesse et renvoie une nouvelle promesse qui est résolue avec la valeur de retour de la fonction utilisée en fonction de la résolution ou non.

Exemples

Créer un objet Promise

Dans le court exemple qui suit, on illustre le mécanisme d'une Promise. La méthode testPromise() est appelée chaque fois qu'on clique sur l'élément <button>. Cette méthode crée une promesse qui sera tenue grâce à la fonction window.setTimeout(), et avec la valeur comptePromesse (nombre commançant à 1) après 1s à 3s (aléatoire). Le constructeur Promise() est utilisé pour créer la promesse.

Le fait que la promesse soit tenue est simplement enregistré via un callback sur p1.then(). Quelques indicateurs illustrent la manière dont la partie synchrone est découplée de la partie asynchrone.

'use strict';
var comptePromesse = 0;

function testPromise() {
  var thisComptePromesse = ++comptePromesse;

  var log = document.getElementById('log');
  log.insertAdjacentHTML('beforeend', thisComptePromesse + 
      ') Started (<small>Début du code synchrone</small>)<br/>');

  // on crée une nouvelle promesse :
  var p1 = new Promise(
    // La fonction de résolution est appelée avec la capacité de 
    // tenir ou de rompre la promesse
    function(resolve, reject) {       
      log.insertAdjacentHTML('beforeend', thisComptePromesse + 
          ') Promise started (<small>Début du code asynchrone</small>)<br/>');

      // Voici un exemple simple pour créer un code asynchrone
      window.setTimeout(
        function() {
          // On tient la promesse !
          resolve(thisComptePromesse);
        }, Math.random() * 2000 + 1000);
    });

  // On définit ce qui se passe quand la promesse est tenue
  // et ce qu'on appelle (uniquement) dans ce cas
  // La méthode catch() définit le traitement à effectuer
  // quand la promesse est rompue.
  p1.then(
    // On affiche un message avec la valeur
    function(val) {
      log.insertAdjacentHTML('beforeend', val +
          ') Promise fulfilled (<small>Fin du code asynchrone</small>)<br/>');
    }).catch(
      // Promesse rejetée
      function() { 
        console.log("promesse rompue");
      });

  log.insertAdjacentHTML('beforeend', thisComptePromesse + 
      ') Promise made (<small>Fin du code synchrone</small>)<br/>');
}

L'exemple s'exécute lorsqu'on clique sur le bouton. Pour tester cet exemple, il est nécessaire d'utiliser un navigateur qui supporte les objets Promise. En cliquant plusieurs fois sur le bouton en peu de temps, on verra qu'il y a plusieurs promesses tenues les une après les autres.

Utiliser XMLHttpRequest() avec une promesse

Dans l'exemple qui suit, on illustre comment utiliser une promesse pour fournir le résultat d'une requête XMLHttpRequest :

'use strict';

// A-> $http cette fonction est implémentée pour respecter le patron
// de conception (pattern) Adaptateur
function $http(url){
 
  // Un exemple d'objet
  var core = {

    // La méthode qui effectue la requête AJAX
    ajax : function (method, url, args) {

      // On établit une promesse en retour
      var promise = new Promise( function (resolve, reject) {

        // On instancie un XMLHttpRequest
        var client = new XMLHttpRequest();
        var uri = url;

        if (args && (method === 'POST' || method === 'PUT')) {
          uri += '?';
          var argcount = 0;
          for (var key in args) {
            if (args.hasOwnProperty(key)) {
              if (argcount++) {
                uri += '&';
              }
              uri += encodeURIComponent(key) + '=' + encodeURIComponent(args[key]);
            }
          }
        }

        client.open(method, uri);
        client.send();

        client.onload = function () {
          if (this.status >= 200 && this.status < 300) {
            // On utilise la fonction "resolve" lorsque this.status vaut 2xx
            resolve(this.response);
          } else {
            // On utilise la fonction "reject" lorsque this.status est différent de 2xx
            reject(this.statusText);
          }
        };
        client.onerror = function () {
          reject(this.statusText);
        };
      });

      // Return the promise
      return promise;
    }
  };

  // Pattern adaptateur
  return {
    'get' : function(args) {
      return core.ajax('GET', url, args);
    },
    'post' : function(args) {
      return core.ajax('POST', url, args);
    },
    'put' : function(args) {
      return core.ajax('PUT', url, args);
    },
    'delete' : function(args) {
      return core.ajax('DELETE', url, args);
    }
  };
};
// Fin de A

// B-> Ici on définit les fonctions et les charges utiles
var mdnAPI = 'https://developer.mozilla.org/en-US/search.json';
var payload = {
  'topic' : 'js',
  'q'     : 'Promise'
};

var callback = {
  success : function(data){
     console.log(1, 'success', JSON.parse(data));
  },
  error : function(data){
     console.log(2, 'error', JSON.parse(data));
  }
};
// End B

// On exécute la méthode
$http(mdnAPI)
  .get(payload)
  .then(callback.success)
  .catch(callback.error);

// Une alternative qui appelle la méthode et permet de gérer le rejet de la promesse différemment
$http(mdnAPI) 
  .get(payload) 
  .then(callback.success, callback.error);

// Une autre alternative pour la gestion du rejet de la promesse
$http(mdnAPI) 
  .get(payload) 
  .then(callback.success)
  .then(undefined, callback.error);

Charger une image en XHR

Un autre exemple simple utilisant Promise et XMLHttpRequest afin de charger une image est disponible sur le dépôt GitHub MDN promise-test. Vous pouvez également consulter le résultat obtenu sur cette page. Chaque étape est commentée afin de vous permettre de suivre l'état de la promesse et l'architecture utilisée avec XHR.

Spécifications

Spécification État Commentaires
ECMAScript 2015 (6th Edition, ECMA-262)
La définition de 'Promise' dans cette spécification.
Standard Définition initiale au sein d'un standard ECMA.
ECMAScript 2017 Draft (ECMA-262)
La définition de 'Promise' dans cette spécification.
Projet  

Compatibilité des navigateurs

Fonctionnalité Chrome Edge Firefox Internet Explorer Opera Safari Servo
Promise32.0(Oui)29.0Aucun support197.1Aucun support
Constructor requires new32.0(Oui)37.0Aucun support1910Aucun support
Promise.all32.0(Oui)29.0Aucun support197.1Aucun support
Promise.prototype32.0(Oui)29.0Aucun support197.1Aucun support
Promise.prototype.catch32.0(Oui)29.0Aucun support197.1Aucun support
Promise.prototype.then32.0(Oui)29.0Aucun support197.1Aucun support
Promise.race32.0(Oui)29.0Aucun support197.1Aucun support
Promise.reject32.0(Oui)29.0Aucun support197.1Aucun support
Promise.resolve32.0(Oui)29.0Aucun support197.1Aucun support
Fonctionnalité Android Chrome for Android Edge Mobile Firefox for Android IE Mobile Opera Mobile Safari Mobile
Promise4.4.432.0(Oui)29Aucun support(Oui)8.0
Constructor requires new4.4.432.0(Oui)37.0Aucun support(Oui)10
Promise.all4.4.432.0(Oui)29Aucun support(Oui)8.0
Promise.prototype4.4.432.0(Oui)29Aucun support(Oui)8.0
Promise.prototype.catch4.4.432.0(Oui)29Aucun support(Oui)8.0
Promise.prototype.then4.4.432.0(Oui)29Aucun support(Oui)8.0
Promise.race4.4.432.0(Oui)29Aucun support(Oui)8.0
Promise.reject4.4.432.0(Oui)29Aucun support(Oui)8.0
Promise.resolve4.4.432.0(Oui)29Aucun support(Oui)8.0

Voir aussi

Étiquettes et contributeurs liés au document

 Contributeurs à cette page : SphinxKnight, VivienZo, sammy44nts, Mr21, toons3000, teoli, neveldo, nicodel, Goofy, P45QU10U
 Dernière mise à jour par : SphinxKnight,