web-dev-qa-db-fra.com

Comment savoir si un objet est une promesse?

Que ce soit une promesse ES6 ou une promesse bluebird, une promesse Q, etc.

Comment puis-je tester pour voir si un objet donné est une promesse?

245
theram

Comment une bibliothèque de promesses décide

Si elle a une fonction .then, il s’agit de la bibliothèque de promesses utilisée par seulement

La spécification Promises/A + a une notion appelée thenable qui est fondamentalement "un objet avec une méthode then". Les promesses vont et devront assimiler n'importe quoi avec une méthode d'alors. Toute la mise en œuvre de la promesse que vous avez mentionnée le fait.

Si nous regardons la spécification :

2.3.3.3 si then est une fonction, appelez-la avec x comme ceci, le premier argument resolPromise et le second argument rejeterPromise

Il explique également la raison de cette décision de conception:

Ce traitement de thenables permet l’interopérabilité des implémentations de promesse, à condition qu’elles exposent une méthode then conforme à Promises/A +. Cela permet également aux implémentations de Promises/A + d'assimiler des implémentations non conformes avec des méthodes raisonnables.

Comment vous devriez décider

Vous ne devriez pas - à la place appeler Promise.resolve(x) (Q(x) dans Q) qui always convertira toute valeur ou thenable externe en une promesse de confiance. Il est plus sûr et plus facile que d'effectuer ces vérifications vous-même. 

vraiment besoin d'être sûr?

Vous pouvez toujours l'exécuter via la suite de tests : D

245
Benjamin Gruenbaum

Vérifier si quelque chose est promis complique inutilement le code, utilisez simplement Promise.resolve

Promise.resolve(valueOrPromiseItDoesntMatter).then(function(value) {

})
122
Esailija

Voici ma réponse initiale, qui a depuis été ratifiée dans la spécification comme moyen de tester une promesse:

Promise.resolve(obj) == obj

Cela fonctionne parce que le algorithm exige explicitement que Promise.resolve doit renvoyer l'objet exact transmis dans if et uniquement si c'est une promesse de la définition de la spéc.

J'ai une autre réponse ici, qui disait cela, mais je l'ai changée en autre chose quand cela ne fonctionnait pas avec Safari à cette époque. C'était il y a un an et cela fonctionne désormais de manière fiable, même dans Safari.

J'aurais modifié ma réponse initiale, sauf que je me sentais mal, étant donné que plus de personnes ont désormais voté pour la solution modifiée dans cette réponse par rapport à la réponse originale. Je crois que c'est la meilleure réponse et j'espère que vous êtes d'accord.

66
jib

Mise à jour: Ce n'est plus la meilleure réponse. Veuillez voter mon autre réponse à la place.

obj instanceof Promise

devrait le faire. Notez que cela ne peut fonctionner de manière fiable qu'avec les promesses es6 natives.

Si vous utilisez un shim, une bibliothèque de promesses ou tout autre élément prétendant ressembler à une promesse, il peut être plus approprié de tester un "thenable" (tout avec une méthode .then), comme indiqué dans d'autres réponses ici.

42
jib
if (typeof thing.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}
39
unobf

Pour voir si l'objet donné est une native ES6 Promise, nous pouvons utiliser ce prédicat:

function isPromise(value) {
  return value && Object.prototype.toString.call(value) === "[object Promise]";
}

Call ing toString directement à partir du Object.prototype renvoie une représentation de chaîne native du type d'objet donné qui est "[object Promise]" dans notre cas. Cela garantit que l'objet donné

  • Contourne les faux positifs tels que ..:
    • Type d'objet auto-défini avec le même nom de constructeur ("Promise").
    • Méthode toString auto-écrite de l'objet donné.
  • Fonctionne dans plusieurs contextes d'environnement (par exemple, iframes) contrairement à instanceof ou isPrototypeOf.
12
Boghyon Hoffmann

Voici le code/ https://github.com/ssnau/xkit/blob/master/util/is-promise.js

!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';

si un objet avec une méthode then, il doit être traité comme un Promise.

6
ssnau

Si vous utilisez TypeScript, j'aimerais ajouter que vous pouvez utiliser la fonctionnalité "type predicate". Vous devriez juste envelopper la vérification logique dans une fonction qui retourne x is Promise<any> et vous n'aurez pas besoin de faire de dactylographie. Ci-dessous, dans mon exemple, c est une promesse ou un de mes types que je souhaite convertir en une promesse en appelant la méthode c.fetch().

export function toPromise(c: Container<any> | Promise<any>): Promise<any> {
    if (c == null) return Promise.resolve();
    return isContainer(c) ? c.fetch() : c;
}

export function isContainer(val: Container<any> | Promise<any>): val is Container<any> {
    return val && (<Container<any>>val).fetch !== undefined;
}

export function isPromise(val: Container<any> | Promise<any>): val is Promise<any> {
    return val && (<Promise<any>>val).then !== undefined;
}

Plus d'infos: https://www.typescriptlang.org/docs/handbook/advanced-types.html

4
Murilo Perrone

Si vous utilisez une méthode asynchrone, vous pouvez le faire et éviter toute ambiguïté.

async myMethod(promiseOrNot){
  const theValue = await promiseOrNot()
}

Si la fonction retourne promis, elle attendra et reviendra avec la valeur résolue. Si la fonction renvoie une valeur, celle-ci sera traitée comme résolue.

Si la fonction ne retourne pas une promesse aujourd'hui, mais si demain en renvoie une ou est déclarée asynchrone, vous serez à l'abri de l'avenir.

3
Steven Spungin
it('should return a promise', function() {
    var result = testedFunctionThatReturnsPromise();
    expect(result).toBeDefined();
    // 3 slightly different ways of verifying a promise
    expect(typeof result.then).toBe('function');
    expect(result instanceof Promise).toBe(true);
    expect(result).toBe(Promise.resolve(result));
});
2
purplecabbage

Pas une réponse à la question complète mais je pense qu'il vaut la peine de mentionner que dans Node.js 10 une nouvelle fonction util nommée isPromise a été ajoutée pour vérifier si un objet est une promesse native ou non:

const utilTypes = require('util').types
const b_Promise = require('bluebird')

utilTypes.isPromise(Promise.resolve(5)) // true
utilTypes.isPromise(b_Promise.resolve(5)) // false
1
LEQADA

Voici comment graphql-js package détecte les promesses:

function isPromise(value) {
  return Boolean(value && typeof value.then === 'function');
}

value est la valeur renvoyée de votre fonction. J'utilise ce code dans mon projet et je n'ai aucun problème jusqu'à présent.

0
muratgozel