# Promise

Le concept de **`Promise`** date des années 70. Les **`Promise`**&#x73; sont parfois appelés **`Future`** ou **`Deferred`**.

En 2010, le développeur Kris Kowal inspire la communauté JavaScript en implémentant ce concept pour NodeJS via la librairie Q <https://github.com/kriskowal/q>. Les implémentations se sont ensuite démultipliées jusqu'à ce que les `Promise`s deviennent un standard avec ES6.

## Fonctionnement des `Promise`s

Le fonctionnement d'une `Promise` est généralement le suivant :

1\. Un appelant fait appel à une fonction qui procède à un traitement asynchrone mais **retourne de façon synchrone** un objet container ***(la `Promise`)*** à l'appelant.

2\. A ce stade, la `Promise` est le plus souvent dans un état "pending".

3\. L'appelant inscrit sur la `Promise` une "callback" de succès pour être informé quand le résultat est disponible (e.g. : `promise.then(data => console.log(data)`) et une callback d'erreur pour être informé de l'échec (e.g. : `promise.catch(error => console.error(error)`).

4\. Quand la fonction appelée obtient le résultat *(ou une erreur)*, elle notifie la `Promise` qui passe alors à un état "resolved" *(ou "rejected")*.

5\. La `Promise` déclenche alors toutes les fonctions de "callback" de succès *(ou d'erreur)* qui ont pu lui être transmises (via les méthodes `.then` et `.catch`).

![How Promise works](/files/-LCZLJP2lfCNfkiDvWQO)

## Consommation d'une `Promise`

A titre d'exemple, nous allons utiliser la fonction `fetch` désormais standard qui vient déloger la poussiéreuse `XMLHttpRequest`.

Cette fonction a la particularité de retourner une `Promise`.

```typescript
fetch('https://www.googleapis.com/books/v1/volumes?q=extreme%20programming')
    .then(response => {
        console.log(response.status);
    });
```

Pour accéder au "body" de la response, il faut utiliser la méthode `Response.json` qui retourne une `Promise` également.

```typescript
fetch('https://www.googleapis.com/books/v1/volumes?q=extreme%20programming')
    .then(response => {
        
        response.json()
            .then(data => {
                console.log(data.totalItems);
            });
        
    });
```

Malheureusement, pour le moment, les problèmes associés au "callbacks waterfall" persistent.

## Chaînage de `Promise`s

Pour éviter les "callbacks waterfall", il est possible de chainer les `Promise`. En effet, les méthodes `Promise.then` et `Promise.catch` retournent des `Promise`s.

### Chaînage synchrone

```typescript
fetch('https://www.googleapis.com/books/v1/volumes?q=extreme%20programming')
    .then(response => response.status)
    .then(status => console.log(status);
```

La ligne 1 retourne une `Promise` contenant la `Response` *(elle est donc de type `Promise<Response>`)*.

La ligne 2 crée à son tour une nouvelle `Promise` déduite de la première et contenant le "status" *(elle est donc de type `Promise<number>`).*

La ligne 3 consomme donc le résultat de la `Promise` précédente.

### Chaînage asynchrone

Une autre propriété intéressante des `Promise` est que **si la valeur retournée** à l'une des étapes **est une `Promise`**, alors l'étape suivante **ne sera appelée que quand la `Promise` sera "resolved"** et elle recevra en paramètre le résultat de résolution.

```typescript
fetch('https://www.googleapis.com/books/v1/volumes?q=extreme%20programming')
    .then(response => response.json())
    .then(data => console.log(totalItems);
```

### Chaînage et gestion d'erreurs

Si une erreur se produit à n'importe quelle étape soit car :

* la `Promise` initiale est "rejected",
* l'une des étapes lève une exception,
* ou l'une des étapes retourne une `Promise` "rejected,

alors **toutes les étapes suivantes sont ignorées** et la "callback" associée au premier "catch" de la chaîne *(à partir de l'erreur)* est appelé.

```typescript
fetch('https://www.googleapis.com/books/v1/volumes?q=extreme%20programming')
    .then(response => response.JSON())
    .then(data => console.log(totalItems))
    .catch(error => console.error(error));
```

Nous obtenons alors l'erreur `response.JSON is not a function` à la ligne 4 *(car la méthode se nomme `json` et non `JSON`)*.

## Création de `Promise`s

Pour créer une `Promise`, il faut instancier la classe `Promise` tel qu'indiqué ci-dessous et appeler la fonction "resolve" avec la donnée de résolution en cas de succès ou la méthode "reject" avec l'objet d'erreur en cas d'échec.

```typescript
const getCurrentCity = () => {

    return new Promise((resolve, reject) => {
    
        /* Simulating some async stuff... */
        setTimeout(() => {
        
            if (hasPermission !== true) {
                reject(new Error('Permission denied!'));
                return;
            }
            
            resolve('Lyon');
        
        }, 1000);
    
    });

};

getCurrentCity()
    .then(city => getWeatherInfo(city))
    .then(weatherInfo => console.log(weatherInfo.temperature))
    .catch(error => console.error(error));
```

{% hint style="warning" %}
Une `Promise` ne peut être "resolved" ou "rejected" qu'une seule fois.

**C'est le premier appel qui gagne** et qui définit donc l'état final de la `Promise`, les appels suivants sont simplement ignorés.
{% endhint %}

> Vivement le jour où les appels superflus de "resolve" et "reject" déclencheront des erreurs.

## Limitation du Scope

Parmi d'autres limitations que nous aborderons plus tard, dans le dernier exemple, on peut remarquer l'indisponibilité de la variable `city` lors du `console.log` de l'étape finale *(ligne 23)*.

Il existe bien sûr des solutions de contournement mais peu séduisantes. Il est préférable d'adopter directement l'approche [Async / Await](/angular/callback-hell-vs.-promise-vs.-async-await/async-await.md) pour éviter ces problèmes.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://guide-angular.wishtack.io/angular/callback-hell-vs.-promise-vs.-async-await/promise.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
