Promise.prototype.then()
========================

La méthode **`then()`**, disponible sur les instances `Promise`, prend jusqu'à deux arguments qui sont les fonctions de rappel respectivement utilisées pour la réussite ou l'échec de la promesse. Cette méthode renvoie immédiatement un objet `Promise` équivalent, ce qui permet d'enchaîner les appels aux autres méthodes des promesses.

Exemple interactif
------------------

Syntaxe
-------


```js
then(siTenue)
then(siTenue, siRejetée)
```

### Paramètres

`siTenue` Facultatif

Une fonction à exécuter de façon asynchrone quand la promesse est tenue. La valeur de retour de cette fonction devient la valeur de réussite de la promesse renvoyée par `then()`. Cette fonction de rappel est appelée avec les arguments suivants :

`valeur`

 La valeur avec laquelle la promesse a été tenue.
 Si cet argument n'est pas une fonction, il est remplacé en interne par la fonction *identité* (`(x) => x`) qui passe la valeur de réussite.



`siRejetée` Facultatif

Une fonction à exécuter de façon asynchrone quand la promesse est rompue. Sa valeur de retour devient la valeur de réussite de la promesse renvoyée par `catch()`. Cette fonction de rappel est appelée avec les arguments suivants :

`raison`

 La valeur avec laquelle la promesse a été rompue.
 Si cet argument n'est pas une fonction, il est remplacé en interne par une fonction de *rejet* (`(x) => { throw x; }`) qui renvoie la raison d'échec qui a été reçue en amont.



### Valeur de retour

Cette méthode renvoie immédiatement un nouvel objet `Promise`. Cette nouvelle promesse est toujours en attente de résolution lorsqu'elle est renvoyée, quel que soit le statut de la promesse courante.

Une des deux fonctions de rappel entre `siTenue()` et `siRejetée()` sera exécutée selon la réussite ou l'échec de la promesse. L'appel est toujours exécuté de façon asynchrone, même si la promesse courante est déjà résolue. Le comportement de la promesse renvoyée (désignée ici avec `p`) dépend du résultat de l'exécution de la fonction de rappel, selon les règles suivantes. Si la fonction de rappel :

* Renvoie une valeur : `p` est réussie avec la valeur de retour.
* Ne renvoie rien : `p` est réussie avec `undefined` comme valeur.
* Lève une erreur : `p` échoue avec l'erreur levée comme valeur.
* Renvoie une promesse déjà réussie : `p` est réussie avec la valeur de réussite de la promesse courante.
* Renvoie une promesse déjà échouée : `p` échoue avec la valeur d'échec de la promesse courante.
* Renvoie une autre promesse en attente : `p` est en attente et réussit/échoue avec la valeur de la promesse courante immédiatement après que celle-ci ait réussi/échoué.
Description
-----------

La méthode `then()` permet de planifier l'exécution des fonctions de rappel pour gérer la résolution d'une promesse (que ce soit une réussite ou un échec). Il s'agit d'une méthode primitive pour les promesses : le protocole *thenable* attend de tous les objets semblables à une promesse qu'ils exposent une méthode `then()`, et les méthodes `catch()` et `finally()` fonctionnent toutes les deux en appelant la méthode `then()`.

Pour plus d'informations à propos du gestionnaire d'échec `siRejetée()`, voir la référence pour la méthode `catch()`.

`then()` renvoie un nouvel objet `Promise`. Si vous appelez la méthode `then()` par deux fois, sur le même objet `Promise` (plutôt que de les enchaîner), vous obtiendrez alors une promesse dotée de deux paires de gestionnaires de réussite/échec. Tous les gestionnaires attachés à une même promesse sont appelés dans l'ordre selon lequel ils ont été ajoutés. Toutefois, les deux promesses renvoyées par chaque appel `then()` engendre deux chaînes séparées qui n'attendent pas la résolution de l'autre.

Les objets dotés d'une méthode `then()` (*thenable*) créés le long d'une chaîne d'appels à `then()` sont toujours résolus. Le gestionnaire `siTenue()` ne reçoit jamais d'objet doté d'une méthode `then()` et toute valeur avec une méthode `then()` renvoyée par l'un des gestionnaires est résolue avant d'être passée au gestionnaire suivant. En effet, lors de la construction d'une promesse, les fonctions de résolution et de rejet passées sont enregistrées et lorsque la promesse courante est terminée, la fonction correspondante est appelée avec la valeur de réussite ou la raison de l'échec. La logique de résolution est déterminée par la fonction passée au constructeur `Promise()`.

`then()` prend en charge les sous-classes, ce qui signifie qu'elle peut être appelée depuis les instances des sous-classes de `Promise`, le résultat sera alors une promesse du type de la sous-classe. Vous pouvez personnaliser le type de la valeur de retour grâce à la propriété `@@species` (en-US).

Exemples
--------

### Utiliser la méthode `then()`


```js
const p1 = new Promise((resoudre, rejeter) => {
  resoudre("Réussite !");
  // ou
  // rejeter(new Error("Erreur !"));
});

p1.then(
  (value) => {
    console.log(value); // Réussite !
  },
  (reason) => {
    console.error(reason); // Erreur !
  },
);
```

### Avoir l'un des paramètres qui n'est pas une fonction


```js
Promise.resolve(1).then(2).then(console.log); // 1
Promise.reject(1).then(2, 2).then(console.log, console.log); // 1
```

### Enchaînement

La méthode `then()` renvoie un nouvel objet `Promise`, ce qui permet d'enchaîner les appels aux méthodes des promesses.

Si la fonction passée à `then()` comme gestionnaire renvoie un objet `Promise`, une promesse équivalente sera exposée à l'appel à `then()` qui suit. Le fragment de code qui suit simule du code asynchrone à l'aide de la fonction `setTimeout()`.


```js
Promise.resolve("toto")
  // 1. On reçoit "toto", on y concatène "truc" et on résout
  // avec la valeur obtenue pour le prochain then
  .then(
    (chaine) =>
      new Promise((resoudre, rejeter) => {
        setTimeout(() => {
          chaine += "truc";
          resoudre(chaine);
        }, 1);
      }),
  )
  // 2. On reçoit "tototruc", on enregistre une fonction de rappel
  // pour manipuler cette chaîne et l'afficher dans la console
  // mais on renverra avant la chaîne non modifiée au prochain then
  .then((chaine) => {
    setTimeout(() => {
      chaine += "machin";
      console.log(chaine); // tototrucmachin
    }, 1);
    return chaine;
  })
  // 3. On affiche des messages sur l'exécution du code dans cette section
  // avant le traitement de la chaîne dans le bloc then() précédent.
  .then((chaine) => {
    console.log(
      "Dernier then(). Oups, on n'a pas pris la peine d'instancier et de renvoyer une promesse dans l'appel then() précédent. L'ordre de la séquence pourrait être surprenant.",
    );

    // On notera qu'ici `chaine` n'a pas le suffixe 'machin'. En effet, nous avons
    // simuler l'attente asynchrone avec une fonction setTimeout()
    console.log(chaine); // tototruc
  });

// Affichera ceci dans la console, dans cet ordre :
// Dernier then(). Oups, on n'a pas pris la peine d'instancier et de renvoyer une promesse dans l'appel then() précédent. L'ordre de la séquence pourrait être surprenant.
// tototruc
// tototrucmachin
```


La valeur renvoyée par `then()` est résolue de la même façon qu'avec `Promise.resolve()`. Cela signifie que les objets avec une méthode `then()` sont pris en charge et que si la valeur de retour n'est pas une promesse, elle est implicitement convertie en un objet `Promise` puis résolue.


```js
const p2 = new Promise((resoudre, rejeter) => {
  resoudre(1);
});

p2.then((valeur) => {
  console.log(valeur); // 1
  return valeur + 1;
}).then((valeur) => {
  console.log(valeur, "- une valeur synchrone fonctionne"); // 2 - une valeur synchrone fonctionne
});

p2.then((valeur) => {
  console.log(valeur); // 1
});
```


Un appel à `then()` renvoie une promesse qui pourra échouer si la fonction déclenche une erreur ou renvoie une promesse rompue.


```js
Promise.resolve()
  .then(() => {
    // On lève une exception pour que .then()
    // renvoie une promesse rompue
    throw new Error("Oh non !");
  })
  .then(
    () => {
      console.log("Pas appelée.");
    },
    (erreur) => {
      console.error(`Fonction siRejetée() appelée : ${erreur.message}`);
    },
  );
```


En pratique, il est plutôt souhaitable d'intercepter les promesses rompues avec `catch()` plutôt que d'utiliser la syntaxe de `then()` avec les deux cas (réussite/échec). Voici un exemple.


```js
Promise.resolve()
  .then(() => {
    // On lève une exception pour que .then()
    // renvoie une promesse rompue
    throw new Error("Oh non !");
  })
  .catch((erreur) => {
    console.error(`Fonction siRejetée() appelée : ${erreur.message}`);
  })
  .then(() => {
    console.log(
      "Je suis toujours appelée, même si la promesse du then() précédent échoue.",
    );
  });
```


Dans tous les autres cas, la promesse renvoyée finit par être tenue. Dans l'exemple qui suit, le premier appel à `then()` renvoie la valeur `42`, enveloppée dans une promesse tenue, même si la promesse précédente dans la chaîne avait été rejetée.


```js
Promise.reject()
  .then(
    () => 99,
    () => 42,
  ) // siRejetée renvoie 42 qui est empaqueté dans une promesse tenue
  .then((solution) => console.log(`Résolue avec ${solution}`)); // Résolue avec 42
```


Si `siTenue()` renvoie une promesse, la valeur de retour de `then()` sera tenue/rompue selon l'état de cette promesse.


```js
function resoudrePlusTard(resoudre, rejeter) {
  setTimeout(() => {
    resoudre(10);
  }, 1000);
}
function rejeterPlusTard(resoudre, rejeter) {
  setTimeout(() => {
    rejeter(new Error("Erreur"));
  }, 1000);
}

const p1 = Promise.resolve("toto");
const p2 = p1.then(() => {
  // On renvoie une promesse qui sera résolue avec la valeur 10 après 1 seconde
  return new Promise(resoudrePlusTard);
});
p2.then(
  (v) => {
    console.log("résolue", v); // "résolue", 10
  },
  (e) => {
    // N'est pas appelée
    console.error("rejetée", e);
  },
);

const p3 = p1.then(() => {
  // On renvoie une promesse qui sera rejetée avec 'Erreur' après 1 seconde
  return new Promise(rejeterPlusTard);
});
p3.then(
  (v) => {
    // N'est pas appelée
    console.log("résolue", v);
  },
  (e) => {
    console.error("rejetée", e); // "rejetée", 'Erreur'
  },
);
```


On peut enchaîner les appels des fonctions qui renvoient des promesses.


```js
function obtenirDonnees() {
  // L'API fetch() renvoie une promesse. Cette fonction
  // renvoie également une promesse sauf qu'on effectue
  // un traitement plus avancé sur la valeur de résolution
  // de la promesse renvoyée.
  return fetch("current-data.json").then((response) => {
    if (response.headers.get("content-type") !== "application/json") {
      throw new TypeError();
    }
    const j = response.json();
    // faire quelque chose avec j

    // La valeur de réussite fournie lorsqu'on
    // appelle obtenirDonnees().then()
    return j;
  });
}
```

### Caractère asynchrone de `then()`

Dans l'exemple qui suit, on illustre le caractère asynchrone de la méthode `then()`.


```js
// Prenons une promesse résolue comme 'promResolue', l'appel à
// 'promResolue.then(…)' renvoie immédiatement une nouvelle promesse,
// mais la fonction de rappel '(value) => {…}' sera appelée de
// façon asynchrone, comme on peut le voir dans la console.
// La nouvelle promesse est affectée à 'promSuivante', cette
// dernière est résolue avec la valeur renvoyée par le gestionnaire.
const promResolue = Promise.resolve(33);
console.log(promResolue);

const promSuivante = promResolue.then((valeur) => {
  console.log(
    `Ceci est appelé après la fin de la pile principale. ` +
      `La valeur reçue est : ${valeur}, la valeur renvoyée est : ${valeur + 1}`,
  );
  return valeur + 1;
});
console.log(promSuivante);

// En utilisant setTimeout(), on peut retarder l'exécution d'une fonction
// jusqu'au moment où la pile des appels est vide
setTimeout(() => {
  console.log(promSuivante);
});

// Le code qui précède, affichera ce qui suit dans cet ordre :
// Promise {[[PromiseStatus]]: "resolved", [[PromiseResult]]: 33}
// Promise {[[PromiseStatus]]: "pending", [[PromiseResult]]: undefined}
// "Ceci est appelé après la fin de la pile principale. La valeur reçue est : 33, la valeur renvoyée est : 34"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseResult]]: 34}
```

Spécifications
--------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.prototype.then |

Compatibilité des navigateurs
-----------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Voir aussi
----------

* `Promise`
* `Promise.prototype.catch()`