Comprendre les promesses JavaScript

Les promesses sont un moyen de gérer le code asynchrone en JavaScript, sans écrire trop de rappels dans votre code.

Introduction aux promesses

Une promesse est généralement définie commeun proxy pour une valeur qui deviendra éventuellement disponible.

Les promesses sont un moyen de gérer le code asynchrone, sans écrire trop de rappels dans votre code.

Bien qu'ils existent depuis des années, ils ont été standardisés et introduits dansES2015, et maintenant ils ont été remplacés dansES2017parfonctions asynchrones.

Fonctions asynchronesutilisez l'API des promesses comme bloc de construction, il est donc fondamental de les comprendre, même si dans un code plus récent, vous utiliserez probablement des fonctions asynchrones au lieu de promesses.

Comment fonctionnent les promesses, en bref

Une fois qu'une promesse a été appelée, elle commencera dansétat en attente. Cela signifie que la fonction appelante continue l'exécution, pendant qu'elle attend la promesse de faire son propre traitement, et donne à la fonction appelante un retour d'information.

À ce stade, la fonction appelante attend qu'elle renvoie la promesse dans unétat résolu, ou dans unétat rejeté, maisla fonction continue son exécution pendant que la promesse fonctionne.

Quelle API JS utilise les promesses?

En plus de votre propre code et code de bibliothèque, les promesses sont utilisées par les API Web modernes standard telles que:

Il est peu probable que dans JavaScript moderne vous vous retrouvezne pasen utilisant les promesses, alors commençons à y plonger.


Créer une promesse

L'API Promise expose un constructeur Promise, que vous initialisez à l'aide denew Promise():

let done = true

const isItDoneYet = new Promise((resolve, reject) => { if (done) { const workDone = ‘Here is the thing I built’ resolve(workDone) } else { const why = ‘Still working on something else’ reject(why) } })

Comme vous pouvez le voir, la promesse vérifie ledonevariable globale, et si c'est vrai, nous retournons une promesse résolue, sinon une promesse rejetée.

Utilisantresolveetrejectnous pouvons renvoyer une valeur, dans le cas ci-dessus, nous renvoyons simplement une chaîne, mais cela pourrait également être un objet.


Consommer une promesse

Dans la dernière section, nous avons présenté comment une promesse est créée.

Voyons maintenant comment la promesse peut êtreconsomméou utilisé.

const isItDoneYet = new Promise()
//...

const checkIfItsDone = () => {
  isItDoneYet
    .then(ok => {
      console.log(ok)
    })
    .catch(err => {
      console.error(err)
    })
}

FonctionnementcheckIfItsDone()exécutera leisItDoneYet()promet et attendra sa résolution, en utilisant lethencallback, et s'il y a une erreur, il la gérera dans lecatchrappeler.


Enchaîner les promesses

Une promesse peut être retournée à une autre promesse, créant une chaîne de promesses.

Un bon exemple d'enchaînement des promesses est donné par leRécupérer l'API, une couche au-dessus de l'API XMLHttpRequest, que nous pouvons utiliser pour obtenir une ressource et mettre en file d'attente une chaîne de promesses à exécuter lorsque la ressource est récupérée.

L'API Fetch est un mécanisme basé sur la promesse et appelantfetch()équivaut à définir notre propre promesse en utilisantnew Promise().

Exemple d'enchaînement des promesses

const status = response => {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  }
  return Promise.reject(new Error(response.statusText))
}

const json = response => response.json()

fetch(’/todos.json’) .then(status) .then(json) .then(data => { console.log(‘Request succeeded with JSON response’, data) }) .catch(error => { console.log(‘Request failed’, error) })

Dans cet exemple, nous appelonsfetch()pour obtenir une liste d'articles TODO à partir dutodos.jsonfichier trouvé dans la racine du domaine, et nous créons une chaîne de promesses.

Fonctionnementfetch()renvoie unréponse, qui a de nombreuses propriétés, et parmi celles que nous référencons:

  • status, une valeur numérique représentant le code d'état HTTP
  • statusText, un message d'état, qui estOKsi la demande réussit

responsea également unjson()méthode, qui renvoie une promesse qui se résoudra avec le contenu du corps traité et transformé enJSON.

Donc, compte tenu de ces prémisses, voici ce qui se passe: la première promesse de la chaîne est une fonction que nous avons définie, appeléestatus(), qui vérifie l'état de la réponse et si ce n'est pas une réponse de succès (entre 200 et 299), il rejette la promesse.

Cette opération amènera la chaîne de promesses à ignorer toutes les promesses enchaînées répertoriées et passera directement à lacatch()en bas, en enregistrant leRequest failedtexte avec le message d'erreur.

Si cela réussit à la place, il appelle lejson()fonction que nous avons définie. Depuis la promesse précédente, en cas de succès, a renvoyé leresponseobjet, nous l'obtenons en tant qu'entrée de la deuxième promesse.

Dans ce cas, nous renvoyons les données traitées par JSON, donc la troisième promesse reçoit directement le JSON:

.then((data) => {
  console.log('Request succeeded with JSON response', data)
})

et nous le connectons à la console.


Gestion des erreurs

Dans l'exemple ci-dessus, dans la section précédente, nous avions uncatchcela a été ajouté à la chaîne des promesses.

Quand quelque chose dans la chaîne des promesses échoue et génère une erreur ou rejette la promesse, le contrôle va au plus prochecatch()déclaration en bas de la chaîne.

new Promise((resolve, reject) => {
  throw new Error('Error')
}).catch(err => {
  console.error(err)
})

// or new Promise((resolve, reject) => { reject(‘Error’) }).catch(err => { console.error(err) })

Erreurs en cascade

Si à l'intérieur ducatch()vous soulevez une erreur, vous pouvez en ajouter une secondecatch()pour le gérer, et ainsi de suite.

new Promise((resolve, reject) => {
  throw new Error('Error')
})
  .catch(err => {
    throw new Error('Error')
  })
  .catch(err => {
    console.error(err)
  })

Orchestrer les promesses

Promise.all()

Si vous avez besoin de synchroniser différentes promesses,Promise.all()vous aide à définir une liste de promesses et à exécuter quelque chose lorsqu'elles sont toutes résolues.

Exemple:

const f1 = fetch('/something.json')
const f2 = fetch('/something2.json')

Promise.all([f1, f2]) .then(res => { console.log(‘Array of results’, res) }) .catch(err => { console.error(err) })

LeMission de déstructuration ES2015la syntaxe vous permet également de faire

Promise.all([f1, f2]).then(([res1, res2]) => {
  console.log('Results', res1, res2)
})

Vous n'êtes pas limité à l'utilisationfetchbien sûr,toute promesse est bonne.

Promise.race()

Promise.race()s'exécute dès qu'une des promesses que vous lui transmettez se résout, et il exécute le rappel joint une seule fois avec le résultat de la première promesse résolue.

Exemple:

const promiseOne = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one')
})
const promiseTwo = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two')
})

Promise.race([promiseOne, promiseTwo]).then(result => { console.log(result) // ‘two’ })

Erreurs courantes

Uncaught TypeError: undefined n'est pas une promesse

Si vous obtenez leUncaught TypeError: undefined is not a promiseerreur dans la console, assurez-vous d'utilisernew Promise()au lieu de justePromise()

Téléchargez mon gratuitManuel du débutant JavaScript


Plus de tutoriels js: