Recherche…
Syntaxe
- nouvelle promesse (/ * fonction d'exécuteur: * / function (resolution, reject) {})
- promise.then (onFulfilled [, onRejected])
- promise.catch (onRejected)
- Promise.resolve (résolution)
- Promise.reject (raison)
- Promise.all (itérable)
- Promise.race (itérable)
Remarques
Les promesses font partie de la spécification ECMAScript 2015 et la prise en charge du navigateur est limitée, avec 88% des navigateurs à travers le monde en juillet 2017. Le tableau suivant donne un aperçu des premières versions de navigateur prenant en charge les promesses.
Chrome | Bord | Firefox | Internet Explorer | Opéra | Opera Mini | Safari | iOS Safari |
---|---|---|---|---|---|---|---|
32 | 12 | 27 | X | 19 | X | 7.1 | 8 |
Dans les environnements qui ne les supportent pas, Promise
peut être polyfilled. Les bibliothèques tierces peuvent également fournir des fonctionnalités étendues, telles que la "promisification" automatisée des fonctions de rappel ou des méthodes supplémentaires telles que la progress
également appelée notify
.
Le site Web standard Promises / A + fournit une liste d'implémentations conformes à 1.0 et 1.1 . Les rappels de promesses basés sur la norme A + sont toujours exécutés de manière asynchrone en tant que microtasques dans la boucle d'événements .
Chaîne de promesse
La méthode then
d'une promesse renvoie une nouvelle promesse.
const promise = new Promise(resolve => setTimeout(resolve, 5000));
promise
// 5 seconds later
.then(() => 2)
// returning a value from a then callback will cause
// the new promise to resolve with this value
.then(value => { /* value === 2 */ });
De retour d' une Promise
d'un then
rappel ajoutera à la chaîne de promesse.
function wait(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
const p = wait(5000).then(() => wait(4000)).then(() => wait(1000));
p.then(() => { /* 10 seconds have passed */ });
Un catch
permet à une promesse rejetée de récupérer, similaire à la manière dont catch
dans une instruction try
/ catch
fonctionne. Tout enchaînée , then
après une catch
exécutera son gestionnaire de résolution en utilisant la valeur résolue de la catch
.
const p = new Promise(resolve => {throw 'oh no'});
p.catch(() => 'oh yes').then(console.log.bind(console)); // outputs "oh yes"
S'il n'y a pas catch
ou reject
les gestionnaires au milieu de la chaîne, une catch
à la fin capturera tout rejet dans la chaîne:
p.catch(() => Promise.reject('oh yes'))
.then(console.log.bind(console)) // won't be called
.catch(console.error.bind(console)); // outputs "oh yes"
Dans certaines occasions, vous pouvez vouloir "brancher" l'exécution des fonctions. Vous pouvez le faire en renvoyant différentes promesses d'une fonction en fonction de la condition. Plus loin dans le code, vous pouvez fusionner toutes ces branches en une seule pour y appeler d'autres fonctions et / ou traiter toutes les erreurs en un seul endroit.
promise
.then(result => {
if (result.condition) {
return handlerFn1()
.then(handlerFn2);
} else if (result.condition2) {
return handlerFn3()
.then(handlerFn4);
} else {
throw new Error("Invalid result");
}
})
.then(handlerFn5)
.catch(err => {
console.error(err);
});
Ainsi, l'ordre d'exécution des fonctions ressemble à ceci:
promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
| ^
V |
-> handlerFn3 -> handlerFn4 -^
La catch
unique aura l'erreur sur n'importe quelle branche.
introduction
Un objet Promise
représente une opération qui a produit ou produira éventuellement une valeur. Les promesses fournissent un moyen robuste d’emballer le résultat (éventuellement en attente) du travail asynchrone, en atténuant le problème des rappels profondément imbriqués (connus sous le nom de « callback hell »).
États et flux de contrôle
Une promesse peut être dans l'un des trois états suivants:
- pending - L'opération sous-jacente n'est pas encore terminée et la promesse est en cours d' exécution.
- réalisé - L'opération est terminée et la promesse est remplie avec une valeur . Cela revient à renvoyer une valeur à partir d'une fonction synchrone.
- rejeté - Une erreur est survenue pendant l'opération et la promesse est rejetée avec un motif . Cela revient à lancer une erreur dans une fonction synchrone.
Une promesse est dite réglée (ou résolue ) lorsqu'elle est remplie ou rejetée. Une fois qu'une promesse est réglée, elle devient immuable et son état ne peut pas changer. Les méthodes then
et catch
d'une promesse peuvent être utilisées pour attacher des callbacks qui s'exécutent quand il est réglé. Ces rappels sont appelés avec la valeur d'exécution et la raison de rejet, respectivement.
Exemple
const promise = new Promise((resolve, reject) => {
// Perform some work (possibly asynchronous)
// ...
if (/* Work has successfully finished and produced "value" */) {
resolve(value);
} else {
// Something went wrong because of "reason"
// The reason is traditionally an Error object, although
// this is not required or enforced.
let reason = new Error(message);
reject(reason);
// Throwing an error also rejects the promise.
throw reason;
}
});
Les méthodes then
et catch
peuvent être utilisées pour joindre des rappels d'exécution et de rejet:
promise.then(value => {
// Work has completed successfully,
// promise has been fulfilled with "value"
}).catch(reason => {
// Something went wrong,
// promise has been rejected with "reason"
});
Remarque: Appeler promise.then(...)
et promise.catch(...)
sur la même promesse peut entraîner une Uncaught exception in Promise
si une erreur survient, que ce soit lors de l'exécution de la promesse ou dans l'un des rappels. le meilleur moyen serait de fixer le prochain auditeur sur la promesse retournée par la précédente then
/ catch
.
Sinon, les deux callbacks peuvent être attachés à un seul appel à then
:
promise.then(onFulfilled, onRejected);
Joindre des rappels à une promesse qui a déjà été réglée les placera immédiatement dans la file d'attente des microtask , et ils seront appelés "dès que possible" (c'est-à-dire immédiatement après le script en cours d'exécution). Il n'est pas nécessaire de vérifier l'état de la promesse avant de joindre des rappels, contrairement à de nombreuses autres implémentations émettant des événements.
Appel de fonction retard
La méthode setTimeout()
appelle une fonction ou évalue une expression après un nombre spécifié de millisecondes. C'est également un moyen trivial de réaliser une opération asynchrone.
Dans cet exemple, l'appel de la fonction wait
résout la promesse après l'heure spécifiée comme premier argument:
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
wait(5000).then(() => {
console.log('5 seconds have passed...');
});
En attente de multiples promesses simultanées
La méthode statique Promise.all()
accepte une itération (par exemple un Array
) de promesses et renvoie une nouvelle promesse, qui se résout lorsque toutes les promesses de l’itérable ont été résolues ou rejetées si au moins une des promesses de l’itérable a été rejetée.
// wait "millis" ms, then resolve with "value"
function resolve(value, milliseconds) {
return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}
// wait "millis" ms, then reject with "reason"
function reject(reason, milliseconds) {
return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
resolve(3, 7000)
]).then(values => console.log(values)); // outputs "[1, 2, 3]" after 7 seconds.
Promise.all([
resolve(1, 5000),
reject('Error!', 6000),
resolve(2, 7000)
]).then(values => console.log(values)) // does not output anything
.catch(reason => console.log(reason)); // outputs "Error!" after 6 seconds.
Les valeurs non prometteuses dans l'itérable sont "promis" .
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
{ hello: 3 }
])
.then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds
L'affectation de destruction peut aider à récupérer les résultats de plusieurs promesses.
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
resolve(3, 7000)
])
.then(([result1, result2, result3]) => {
console.log(result1);
console.log(result2);
console.log(result3);
});
En attendant la première des multiples promesses simultanées
La méthode statique Promise.race()
accepte une itération de Promises et renvoie une nouvelle promesse qui résout ou rejette dès que la première des promesses de l'itérable a été résolue ou rejetée.
// wait "milliseconds" milliseconds, then resolve with "value"
function resolve(value, milliseconds) {
return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}
// wait "milliseconds" milliseconds, then reject with "reason"
function reject(reason, milliseconds) {
return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}
Promise.race([
resolve(1, 5000),
resolve(2, 3000),
resolve(3, 1000)
])
.then(value => console.log(value)); // outputs "3" after 1 second.
Promise.race([
reject(new Error('bad things!'), 1000),
resolve(2, 2000)
])
.then(value => console.log(value)) // does not output anything
.catch(error => console.log(error.message)); // outputs "bad things!" after 1 second
Valeurs "prometteuses"
La méthode statique Promise.resolve
peut être utilisée pour envelopper des valeurs dans des promesses.
let resolved = Promise.resolve(2);
resolved.then(value => {
// immediately invoked
// value === 2
});
Si value
est déjà une promesse, Promise.resolve
simplement.
let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
let two = Promise.resolve(one);
two.then(value => {
// 1 second has passed
// value === 2
});
En fait, value
peut être n'importe quel "thenable" (objet définissant une méthode then
qui fonctionne suffisamment comme une promesse conforme aux spécifications). Cela permet à Promise.resolve
de convertir des objets tiers non approuvés en promesses de confiance de tiers.
let resolved = Promise.resolve({
then(onResolved) {
onResolved(2);
}
});
resolved.then(value => {
// immediately invoked
// value === 2
});
La méthode statique Promise.reject
renvoie une promesse qui rejette immédiatement avec la reason
donnée.
let rejected = Promise.reject("Oops!");
rejected.catch(reason => {
// immediately invoked
// reason === "Oops!"
});
Fonctions "prometteuses" avec rappels
Étant donné une fonction qui accepte un rappel de style Node,
fooFn(options, function callback(err, result) { ... });
vous pouvez le promettre (le convertir en une fonction basée sur les promesses) comme ceci:
function promiseFooFn(options) {
return new Promise((resolve, reject) =>
fooFn(options, (err, result) =>
// If there's an error, reject; otherwise resolve
err ? reject(err) : resolve(result)
)
);
}
Cette fonction peut alors être utilisée comme suit:
promiseFooFn(options).then(result => {
// success!
}).catch(err => {
// error!
});
De manière plus générique, voici comment promouvoir toute fonction de style de rappel donnée:
function promisify(func) {
return function(...args) {
return new Promise((resolve, reject) => {
func(...args, (err, result) => err ? reject(err) : resolve(result));
});
}
}
Cela peut être utilisé comme ceci:
const fs = require('fs');
const promisedStat = promisify(fs.stat.bind(fs));
promisedStat('/foo/bar')
.then(stat => console.log('STATE', stat))
.catch(err => console.log('ERROR', err));
La gestion des erreurs
Les erreurs générées par les promesses sont gérées par le second paramètre ( reject
) passé à then
ou par le gestionnaire transmis à catch
:
throwErrorAsync()
.then(null, error => { /* handle error here */ });
// or
throwErrorAsync()
.catch(error => { /* handle error here */ });
Chaînage
Si vous avez une chaîne de promesses, une erreur provoquera l' resolve
gestionnaires de resolve
:
throwErrorAsync()
.then(() => { /* never called */ })
.catch(error => { /* handle error here */ });
La même chose s'applique à vos fonctions then
. Si un gestionnaire de resolve
renvoie une exception, le gestionnaire de reject
suivant sera appelé:
doSomethingAsync()
.then(result => { throwErrorSync(); })
.then(() => { /* never called */ })
.catch(error => { /* handle error from throwErrorSync() */ });
Un gestionnaire d'erreur renvoie une nouvelle promesse, vous permettant de continuer une chaîne de promesses. La promesse renvoyée par le gestionnaire d'erreurs est résolue avec la valeur renvoyée par le gestionnaire:
throwErrorAsync()
.catch(error => { /* handle error here */; return result; })
.then(result => { /* handle result here */ });
Vous pouvez laisser une erreur tomber en cascade sur une chaîne de promesses en relançant l'erreur:
throwErrorAsync()
.catch(error => {
/* handle error from throwErrorAsync() */
throw error;
})
.then(() => { /* will not be called if there's an error */ })
.catch(error => { /* will get called with the same error */ });
Il est possible de lancer une exception qui n'est pas gérée par la promesse en encapsulant l'instruction throw
dans un rappel setTimeout
:
new Promise((resolve, reject) => {
setTimeout(() => { throw new Error(); });
});
Cela fonctionne car les promesses ne peuvent pas gérer les exceptions lancées de manière asynchrone.
Rejets non gérés
Une erreur sera ignorée en silence si une promesse n'a pas de bloc catch
ou de gestionnaire de reject
:
throwErrorAsync()
.then(() => { /* will not be called */ });
// error silently ignored
Pour éviter cela, utilisez toujours un bloc catch
:
throwErrorAsync()
.then(() => { /* will not be called */ })
.catch(error => { /* handle error*/ });
// or
throwErrorAsync()
.then(() => { /* will not be called */ }, error => { /* handle error*/ });
Autrement, abonnez-vous à l'événement unhandledrejection
pour détecter toute promesse rejetée non gérée:
window.addEventListener('unhandledrejection', event => {});
Certaines promesses peuvent gérer leur rejet après leur création. L'événement de rejectionhandled
est déclenché chaque fois qu'une telle promesse est gérée:
window.addEventListener('unhandledrejection', event => console.log('unhandled'));
window.addEventListener('rejectionhandled', event => console.log('handled'));
var p = Promise.reject('test');
setTimeout(() => p.catch(console.log), 1000);
// Will print 'unhandled', and after one second 'test' and 'handled'
L'argument d' event
contient des informations sur le rejet. event.reason
est l'objet d'erreur et event.promise
est l'objet prometteur ayant provoqué l'événement.
En NodeJS les rejectionhandled
et unhandledrejection
événements sont appelés rejectionHandled
et unhandledRejection
sur process
, respectivement, et ont une signature différente:
process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});
L'argument reason
est l'objet erreur et l'argument promise
une référence à l'objet prometteur qui a déclenché l'événement.
L'utilisation de ces événements unhandledrejection
et rejectionhandled
doit être considérée uniquement à des fins de débogage. En règle générale, toutes les promesses doivent gérer leurs rejets.
Note: À l' heure actuelle, seul le soutien Chrome 49+ et Node.js unhandledrejection
et rejectionhandled
événements.
Mises en garde
Enchaînement avec fulfill
et reject
La fonction then(fulfill, reject)
(avec les deux paramètres non null
) a un comportement unique et complexe, et ne devrait pas être utilisé à moins de savoir exactement comment cela fonctionne.
La fonction fonctionne comme prévu si on lui donne la valeur null
pour l'une des entrées:
// the following calls are equivalent
promise.then(fulfill, null)
promise.then(fulfill)
// the following calls are also equivalent
promise.then(null, reject)
promise.catch(reject)
Toutefois, il adopte un comportement unique lorsque les deux entrées sont données:
// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.then(fulfill).catch(reject)
// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.catch(reject).then(fulfill)
La fonction then(fulfill, reject)
ressemble à un raccourci pour then(fulfill).catch(reject)
, mais ce n’est pas le cas et cela posera des problèmes si elle est utilisée de manière interchangeable. Un tel problème est que le reject
gestionnaire ne gère pas les erreurs de la fulfill
gestionnaire. Voici ce qui va arriver:
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }, // error in the fulfill handler
error => { /* this is not called! */ });
Le code ci-dessus entraînera une promesse rejetée parce que l'erreur est propagée. Comparez-le au code suivant, ce qui aboutit à une promesse remplie:
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }) // error in the fulfill handler
.catch(error => { /* handle error */ });
Un problème similaire existe quand on utilise then(fulfill, reject)
indifféremment avec catch(reject).then(fulfill)
, sauf avec la propagation de promesses remplies au lieu de promesses rejetées.
Lancer de manière synchrone à partir d'une fonction qui devrait renvoyer une promesse
Imaginez une fonction comme celle-ci:
function foo(arg) {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
Si une telle fonction est utilisée au milieu d'une chaîne de promesses, alors apparemment, il n'y a pas de problème:
makeSomethingAsync().
.then(() => foo('unexpectedValue'))
.catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here
Cependant, si la même fonction est appelée en dehors d’une chaîne de promesses, l’erreur ne sera pas gérée et sera envoyée à l’application:
foo('unexpectedValue') // <-- error will be thrown, so the application will crash
.then(makeSomethingAsync) // <-- will not run
.catch(err => console.log(err)) // <-- will not catch
Il y a 2 solutions possibles:
Renvoyer une promesse rejetée avec l'erreur
Au lieu de lancer, procédez comme suit:
function foo(arg) {
if (arg === 'unexepectedValue') {
return Promise.reject(new Error('UnexpectedValue'))
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
Enveloppez votre fonction dans une chaîne de promesses
Votre déclaration de throw
sera correctement capturée lorsqu'elle se trouve déjà dans une chaîne de promesses:
function foo(arg) {
return Promise.resolve()
.then(() => {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
})
}
Réconciliation des opérations synchrones et asynchrones
Dans certains cas, vous pouvez vouloir envelopper une opération synchrone dans une promesse pour empêcher la répétition dans les branches de code. Prenons cet exemple:
if (result) { // if we already have a result
processResult(result); // process it
} else {
fetchResult().then(processResult);
}
Les branches synchrone et asynchrone du code ci-dessus peuvent être conciliées en encapsulant de manière redondante l'opération synchrone dans une promesse:
var fetch = result
? Promise.resolve(result)
: fetchResult();
fetch.then(processResult);
Lors de la mise en cache du résultat d'un appel asynchrone, il est préférable de mettre en cache la promesse plutôt que le résultat lui-même. Cela garantit qu'une seule opération asynchrone est requise pour résoudre plusieurs requêtes parallèles.
Il faut veiller à invalider les valeurs mises en cache lorsque des conditions d'erreur sont rencontrées.
// A resource that is not expected to change frequently
var planets = 'http://swapi.co/api/planets/';
// The cached promise, or null
var cachedPromise;
function fetchResult() {
if (!cachedPromise) {
cachedPromise = fetch(planets)
.catch(function (e) {
// Invalidate the current result to retry on the next fetch
cachedPromise = null;
// re-raise the error to propagate it to callers
throw e;
});
}
return cachedPromise;
}
Réduire un tableau à des promesses chaînées
Ce modèle de conception est utile pour générer une séquence d'actions asynchrones à partir d'une liste d'éléments.
Il existe deux variantes:
- la réduction "alors", qui construit une chaîne qui continue tant que la chaîne connaît le succès.
- la réduction "catch", qui construit une chaîne qui se poursuit tant que la chaîne subit une erreur.
La réduction "alors"
Cette variante du modèle crée une chaîne .then()
et peut être utilisée pour chaîner des animations ou créer une séquence de requêtes HTTP dépendantes.
[1, 3, 5, 7, 9].reduce((seq, n) => {
return seq.then(() => {
console.log(n);
return new Promise(res => setTimeout(res, 1000));
});
}, Promise.resolve()).then(
() => console.log('done'),
(e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals
Explication:
- Nous appelons
.reduce()
sur un tableau source et fournissonsPromise.resolve()
comme valeur initiale. - Chaque élément réduit ajoutera un
.then()
à la valeur initiale. -
reduce()
produit de sera Promise.resolve (). puis (...). puis (...). - Nous
.then(successHandler, errorHandler)
manuellement un.then(successHandler, errorHandler)
après lesuccessHandler
, pour exécutersuccessHandler
une fois toutes les étapes précédentes résolues. Si une étape devait échouer, alorserrorHandler
s'exécuterait.
Note: La réduction "then" est une contrepartie séquentielle de Promise.all()
.
La réduction "catch"
Cette variante du modèle .catch()
une chaîne .catch()
et peut être utilisée pour sonder de manière séquentielle un ensemble de serveurs Web pour certaines ressources mises en miroir jusqu'à ce qu'un serveur opérationnel soit trouvé.
var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
return seq.catch(() => {
console.log(n);
if(n === working_resource) { // 5 is working
return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
} else { // all other values are not working
return new Promise((resolve, reject) => setTimeout(reject, 1000));
}
});
}, Promise.reject()).then(
(n) => console.log('success at: ' + n),
() => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals
Explication:
- Nous appelons
.reduce()
sur un tableau source et fournissonsPromise.reject()
comme valeur initiale. - Chaque élément réduit ajoutera un
.catch()
à la valeur initiale. -
reduce()
du produit seraPromise.reject().catch(...).catch(...)
. - Nous
.then(successHandler, errorHandler)
manuellement.then(successHandler, errorHandler)
après la réduction, pour exécutersuccessHandler
une fois les étapes précédentes résolues. Si toutes les étapeserrorHandler
, alorserrorHandler
s'exécuterait.
Remarque: La réduction "catch" est une contrepartie séquentielle de Promise.any()
(telle qu'elle est implémentée dans bluebird.js
, mais pas dans ECMAScript natif).
pourChaque avec des promesses
Il est possible d'appliquer efficacement une fonction ( cb
) qui renvoie une promesse à chaque élément d'un tableau, chaque élément devant être traité jusqu'à ce que l'élément précédent soit traité.
function promiseForEach(arr, cb) {
var i = 0;
var nextPromise = function () {
if (i >= arr.length) {
// Processing finished.
return;
}
// Process next function. Wrap in `Promise.resolve` in case
// the function does not return a promise
var newPromise = Promise.resolve(cb(arr[i], i));
i++;
// Chain to finish processing.
return newPromise.then(nextPromise);
};
// Kick off the chain.
return Promise.resolve().then(nextPromise);
};
Cela peut être utile si vous devez traiter efficacement des milliers d'éléments, un à la fois. Utiliser une boucle régulière for
créer les promesses les créera toutes en même temps et absorbera une quantité importante de RAM.
Effectuer un nettoyage avec finally ()
Il y a actuellement une proposition (pas encore partie de la norme ECMAScript) pour ajouter un finally
rappel à des promesses qui seront exécutées indépendamment du fait que la promesse est remplie ou rejetée. Sémantiquement, cela est similaire à la clause finally
du bloc try
.
Vous utiliseriez généralement cette fonctionnalité pour le nettoyage:
var loadingData = true;
fetch('/data')
.then(result => processData(result.data))
.catch(error => console.error(error))
.finally(() => {
loadingData = false;
});
Il est important de noter que le rappel finally
n’affecte pas l’état de la promesse. Peu importe la valeur qu'il retourne, la promesse reste dans l'état satisfait / rejeté qu'elle avait auparavant. Ainsi, dans l'exemple ci-dessus, la promesse sera résolue avec la valeur de retour de processData(result.data)
même si le rappel finally
renvoyé n'est undefined
.
Avec le processus de normalisation étant toujours en cours, vos promesses mise en œuvre le plus probable ne soutiendra finally
Demandes de rappel de la boîte. Pour les rappels synchrones, vous pouvez toutefois ajouter cette fonctionnalité avec un polyfill:
if (!Promise.prototype.finally) {
Promise.prototype.finally = function(callback) {
return this.then(result => {
callback();
return result;
}, error => {
callback();
throw error;
});
};
}
Demande d'API asynchrone
Ceci est un exemple d'un simple appel d'API GET
enveloppé d'une promesse de tirer parti de ses fonctionnalités asynchrones.
var get = function(path) {
return new Promise(function(resolve, reject) {
let request = new XMLHttpRequest();
request.open('GET', path);
request.onload = resolve;
request.onerror = reject;
request.send();
});
};
Une gestion des erreurs plus robuste peut être effectuée à l'aide des fonctions onload
et onerror
suivantes.
request.onload = function() {
if (this.status >= 200 && this.status < 300) {
if(request.response) {
// Assuming a successful call returns JSON
resolve(JSON.parse(request.response));
} else {
resolve();
} else {
reject({
'status': this.status,
'message': request.statusText
});
}
};
request.onerror = function() {
reject({
'status': this.status,
'message': request.statusText
});
};
Utilisation de l'ES2017 async / waiting
Le même exemple ci-dessus, Image loading , peut être écrit en utilisant des fonctions asynchrones . Cela permet également d'utiliser la méthode try/catch
pour la gestion des exceptions.
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', () => {
reject(new Error(`Failed to load ${url}`));
});
img.src = url;
});
}
(async () => {
// load /image.png and append to #image-holder, otherwise throw error
try {
let img = await loadImage('http://example.com/image.png');
document.getElementById('image-holder').appendChild(img);
}
catch (error) {
console.error(error);
}
})();