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.

Diagramme de promesse

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.


Démo en direct

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:

  1. Nous appelons .reduce() sur un tableau source et fournissons Promise.resolve() comme valeur initiale.
  2. Chaque élément réduit ajoutera un .then() à la valeur initiale.
  3. reduce() produit de sera Promise.resolve (). puis (...). puis (...).
  4. Nous .then(successHandler, errorHandler) manuellement un .then(successHandler, errorHandler) après le successHandler , pour exécuter successHandler une fois toutes les étapes précédentes résolues. Si une étape devait échouer, alors errorHandler 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:

  1. Nous appelons .reduce() sur un tableau source et fournissons Promise.reject() comme valeur initiale.
  2. Chaque élément réduit ajoutera un .catch() à la valeur initiale.
  3. reduce() du produit sera Promise.reject().catch(...).catch(...) .
  4. Nous .then(successHandler, errorHandler) manuellement .then(successHandler, errorHandler) après la réduction, pour exécuter successHandler une fois les étapes précédentes résolues. Si toutes les étapes errorHandler , alors errorHandler 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.

Remarque: à partir d'avril 2017, les versions actuelles de tous les navigateurs sauf Internet Explorer prennent en charge les fonctions asynchrones .

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);
    }

})();


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow