J'ai une pure promesse JavaScript (implémentation intégrée ou poly-fill):
var promise = new Promise(function (resolve, reject) { /* ... */ });
À partir de la spécification , une promesse peut être l'une des suivantes:
- 'réglé' et 'résolu'
- 'réglé' et 'rejeté'
- 'en attente'
J'ai un cas d'utilisation où je souhaite interroger la promesse de manière synchrone et déterminer:
la promesse est-elle réglée?
si oui, la promesse est-elle résolue?
Je sais que je peux utiliser #then()
pour planifier le travail à effectuer de manière asynchrone après le changement d'état de la promesse. Je ne demande PAS comment faire cela.
Cette question concerne spécifiquement l' interrogation synchrone de l'état d'une promesse . Comment puis-je atteindre cet objectif?
javascript
promise
es6-promise
jokeyrhyme
la source
la source
var promiseStatus = NEW_PRIVATE("Promise#status");
,PromiseSet
fonction àSET_PRIVATE(promise, promiseStatus, status);
console.log(Promise.new((resolve, reject) => {})
=>Promise { <pending> }
Réponses:
Aucune API d'inspection synchrone de ce type n'existe pour les promesses JavaScript natives. Il est impossible de faire cela avec des promesses natives. La spécification ne spécifie pas une telle méthode.
Les bibliothèques Userland peuvent le faire, et si vous ciblez un moteur spécifique (comme la v8) et avez accès au code de la plate-forme (c'est-à-dire que vous pouvez écrire du code dans le noyau ), vous pouvez utiliser des outils spécifiques (comme des symboles privés) pour y parvenir. . C'est super spécifique cependant et pas dans le userland.
la source
.any
place et faire une erreur parce que Mark a insisté. D'une part,Promise.race([])
est une promesse en suspens pour toujours (et non une erreur), vous voulez généralement la première promesse réussie et pas seulement la première promesse. Quoi qu'il en soit, ce n'est pas vraiment pertinent par rapport à la question posée - OP a posé une question sur l'inspection synchrone et non sur.race
ses nombreuses lacunes.MakeQueryablePromise(Promise.resolve(3)).isResolved
est fausse mais la promesse est bien évidemment résolue. Sans oublier que la réponse utilise également les termes «résolu» et «rempli» de manière incorrecte. Pour ce faire, vous pouvez simplement ajouter un.then
gestionnaire vous-même - ce qui manque complètement le point d'inspection synchrone.promise-status-async fait l'affaire. Il est asynchrone mais il ne sert pas
then
à attendre que la promesse soit résolue.la source
Non, pas d'API de synchronisation, mais voici ma version de l'async
promiseState
(avec l'aide de @Matthijs):la source
Promise.race([ Promise.resolve(p).then(() => "fulfilled", () => "rejected"), Promise.resolve().then(() => "pending") ]);
que cela me semble plus sûr:const t = {}; return Promise.race([p,t]).then(v => v === t ? "pending" : "fulfilled", () => "rejected")
et évite de créer des promesses supplémentaires qui persistent tant que le p original est en attente.Vous pouvez faire une course avec Promise.resolve
Ce n'est pas synchrone mais se produit maintenant
Un petit script pour tester et comprendre leur signification de asynchrone
résultats avec delay (0) (commenter le while in delay)
et les résultats de ce test avec firefox (chrome garde l'ordre)
promiseState crée .race et .then: Niveau 2
la source
'a value that p should not return'
, utilisez un symboleSymbol
serait une valeur unique, vous n'aurez donc jamais à deviner quelle "valeur [...] p ne doit pas retourner". Cependant, une référence à un objet spécifique fonctionnerait tout aussi bien.Vous pouvez utiliser un hack (laid) dans Node.js jusqu'à ce qu'une méthode native soit proposée:
la source
Promise.prototype.isPending = function(){ return util.inspect(this).indexOf("<pending>")>-1; }
process.binding('util').getPromiseDetails
Promise.resolve('<pending>')
.dans le nœud, disons interne non documenté
process.binding('util').getPromiseDetails(promise)
la source
Mise à jour: 2019
Bluebird.js propose ceci: http://bluebirdjs.com/docs/api/isfulfilled.html
Si vous préférez créer votre propre wrapper, voici un joli blog à ce sujet.
Parce que JavaScript est monothread, il est difficile de trouver un cas d'utilisation assez courant pour justifier de le placer dans la spécification. Le meilleur endroit pour savoir si une promesse est résolue est dans .then (). Tester si une promesse est remplie créerait une boucle d'interrogation qui est probablement la mauvaise direction.
async / await est une construction intéressante si vous souhaitez raisonner le code async de manière synchrone.
Un autre appel utile est Promise.all ()
Quand j'ai atteint cette réponse pour la première fois, c'est le cas d'utilisation que je recherchais.
la source
Vous pouvez conclure vos promesses de cette façon
la source
.then
exécute toujours de manière asynchrone OP qui veut inspecter une promesse dans le même tour n'obtiendra pas le résultat correct ici. Remarque OP a posé des questions spécifiquement sur l' inspection synchrone et a mentionné qu'il connaissait déjà l'inspection asynchrone.Il est en effet assez ennuyeux que cette fonctionnalité de base manque. Si vous utilisez node.js, je connais deux solutions de contournement, ni l'une ni l'autre très jolie. Les deux extraits ci-dessous implémentent la même API:
Il ne semble pas y avoir de moyen de distinguer les deux derniers états de promesse en utilisant l'une ou l'autre astuce.
1. Utilisez l'API de débogage V8
C'est la même astuce qui
util.inspect
utilise.2. Microtâches exécutées de manière synchrone
Cela évite l'API de débogage, mais présente une sémantique effrayante en provoquant l'
process.nextTick
exécution synchrone de toutes les microtâches et rappels en attente . Elle a également pour effet secondaire d'empêcher l'erreur de «rejet de promesse non gérée» d'être déclenchée pour la promesse inspectée.la source
process._tickCallback
(ou même de% RunMicrotick) - cela cassera aléatoirement des choses dans votre code. J'ai désespérément essayé de le faire fonctionner (pour les faux minuteurs dans les fonctions asynchrones, principalement) et ce n'était jamais assez stable du côté du nœud. J'ai en quelque sorte renoncé à y travailler. L'API de miroir de débogage V8 est tout à fait appropriée ici.DeprecationWarning: DebugContext has been deprecated and will be removed in a future version.
:( On dirait que V8 l'a enlevéprocess.binding('util').getPromiseDetails( promise )
retours[ 0, ]
pour en attente,[ 1, value ]
pour rempli et[ 2, value ]
pour rejeté.Attention: cette méthode utilise des composants internes Node.js non documentés et peut être modifiée sans avertissement.
Dans Node, vous pouvez déterminer de manière synchrone l'état d'une promesse à l'aide de
process.binding('util').getPromiseDetails(/* promise */);
.Cela retournera:
[0, ]
pour en attente,[1, /* value */]
pour accompli, ou[2, /* value */]
pour rejeté.Enveloppant ceci dans une fonction d'assistance:
la source
jest
(c'est le seul endroit qui m'intéresse, vraiment). La fonction existe, mais semble toujours revenirundefined
. Comment savoir ce qui ne va pas?mocha
; jamais essayé avecjest
cependant. Peut-être commencer une nouvelle question de lien ici et inclure votre version Node.js ainsi que lajest
version?Promise
que je n'utilisais que pour tester des choses qui devraient se dérouler pendant qu'unePromise
est en attente, mais j'ai pensé tant que ce que j'ai écrit fonctionne, alors il n'est pas nécessaire de le tester en plus de ce qui en dépend.ce que vous pouvez faire, c'est utiliser une variable pour stocker l'état, définir manuellement l'état sur cette variable et vérifier cette variable.
bien sûr, cela signifie que vous devez avoir accès au code original de la promesse. Sinon, vous pouvez faire:
Ma solution est plus de codage, mais je pense que vous n'auriez probablement pas à le faire pour chaque promesse que vous utilisez.
la source
À partir de la version 8 de Node.js, vous pouvez désormais utiliser le package sage-inspection pour inspecter de manière synchrone les promesses natives (sans aucun piratage dangereux).
la source
Vous pouvez ajouter une méthode à Promise.prototype. Cela ressemble à ceci:
Modifié: La première solution ne fonctionne pas correctement, comme la plupart des réponses ici. Il renvoie «en attente» jusqu'à ce que la fonction asynchrone «.then» soit appelée, ce qui ne se produit pas immédiatement. (Il en va de même pour les solutions utilisant Promise.race). Ma deuxième solution résout ce problème.
Vous pouvez l'utiliser sur n'importe quelle promesse. Par exemple:
Deuxième solution (et correcte):
Et utilisez-le:
Remarque : Dans cette solution, vous n'avez pas besoin d'utiliser l'opérateur "new".
la source
Voici une version es6 plus étoffée de QueryablePromise, permettant la possibilité de chaîner ensuite et d'attraper après la première résolution et de résoudre ou de rejeter immédiatement pour garder l'API cohérente avec la promesse native.
la source
await
utilisation à la réponse de @ jib , avec prototypage idiomatique.notez que cette fonction asynchrone exécute "presque" immédiatement comme une fonction synchronisée (ou peut-être même instantanément).
la source
2019:
Le moyen le plus simple de le faire, comme je le sais, est
thenable
une enveloppe super fine autour de la promesse ou de tout travail asynchrone.la source
Vous pouvez créer votre propre sous-classe, par exemple
QueryablePromise
, en héritant de laPromise
classe disponible nativement , dont les instances auraient unestatus
propriété disponible que vous pouvez utiliser pour interroger l'état des objets de promesse de manière synchrone . Une implémentation de celui-ci peut être vue ci-dessous ou se référer à ceci pour une meilleure explication.la source
fetch
il renverra une promesse native. Comment votre classe vous aiderait-elle?const queryableFetch = new QueryablePromise((resolve, reject) => {fetch(/.../).then((data) => resolve(data)) })
? Ou y a-t-il un problème avec cela? : /, err => reject(err)
comme deuxième argument dethen
ou cela ne propagera pas correctement les erreurs (parmi les raisons pour lesquelles il est considéré comme l' anti-modèle du constructeur de promesse ). Ce n'est pas vraiment synchrone (par exemple, ne détecte pas une promesse déjà résolue), mais peut-être utile dans les cas où vous ne contrôlez pas l'appelant et que la réponse est nécessaire immédiatement.Il y a une autre élégante façon et hacky de vérifier si une promesse est toujours en attente juste en convertissant l'objet entier à la chaîne et vérifiez avec l'aide de l' inspection comme ceci:
util.inspect(myPromise).includes("pending")
.Testé sur Node.js 8,9,10,11,12,13
Voici un exemple complet
Résultat:
la source
Si vous utilisez ES7 expérimental, vous pouvez utiliser async pour encapsuler facilement la promesse que vous souhaitez écouter.
la source
J'ai écrit un petit package npm, promise-value, qui fournit un wrapper de promesse avec un
resolved
indicateur:https://www.npmjs.com/package/promise-value
Il donne également un accès synchrone à la valeur de promesse (ou erreur). Cela ne modifie pas l'objet Promise lui-même, en suivant le modèle d'habillage plutôt que d'étendre.
la source
C'est une question plus ancienne mais j'essayais de faire quelque chose de similaire. J'ai besoin de garder n travailleurs. Ils sont structurés dans une promesse. Je dois scanner et voir s'ils sont résolus, rejetés ou toujours en attente. Si résolu, j'ai besoin de la valeur, si rejeté, faites quelque chose pour corriger le problème ou en attente. En cas de résolution ou de rejet, je dois commencer une autre tâche pour continuer. Je ne peux pas trouver un moyen de le faire avec Promise.all ou Promise.race car je continue à travailler les promesses dans un tableau et ne trouve aucun moyen de les supprimer. Alors je crée un ouvrier qui fait l'affaire
J'ai besoin d'une fonction de générateur de promesse qui renvoie une promesse qui résout ou rejette si nécessaire. Il est appelé par une fonction qui met en place le cadre pour savoir ce que fait la promesse.
Dans le code ci-dessous, le générateur renvoie simplement une promesse basée sur setTimeout.
C'est ici
doWork renvoie un objet contenant la promesse, son état et sa valeur retournée.
Le code suivant exécute une boucle qui teste l'état et crée de nouveaux nœuds de calcul pour le maintenir à 3 nœuds de calcul en cours d'exécution.
Testé dans node.js
BTW Pas tellement dans cette réponse, mais dans d'autres sur des sujets similaires, je déteste quand quelqu'un dit «vous ne comprenez pas» ou «ce n'est pas comme ça que ça marche». Je suppose généralement que le questionneur sait ce qu'il veut. Suggérer une meilleure façon, c'est super. Une explication patiente du fonctionnement des promesses serait également une bonne chose.
la source
J'ai trouvé que cette solution était simple et me permettait de continuer à utiliser les promesses natives tout en ajoutant des vérifications synchrones utiles. Je n'avais pas non plus besoin de récupérer une bibliothèque de promesses complète.
CAVEAT: Cela ne fonctionne que s'il y a une sorte de rupture dans le thread d'exécution actuel pour permettre aux promesses de s'exécuter AVANT de vérifier les constructions synchrones. Cela rend cela d'une utilité plus limitée que je ne le pensais initialement - toujours utile pour mon cas d'utilisation (merci à Benjamin Gruenbaum pour l'avoir signalé)
De https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved qui a basé leur réponse sur Y a-t-il un moyen de dire si une promesse ES6 est remplie / rejetée / résolue?
la source
MakeQueryablePromise(Promise.resolve(3)).isResolved
c'est faux mais la promesse est bien évidemment résolue. Sans oublier que la réponse utilise également les termes «résolu» et «rempli» de manière incorrecte. Pour ce faire, vous pouvez simplement ajouter un.then
gestionnaire vous-même - ce qui manque complètement le point d'inspection synchrone.let wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);
Et tant que vous faites cela, cela fonctionne bien. Mais vous devez comprendre ce fait pour que cela soit utile. Je mettrai à jour la description avec cette mise en garde. Je conviens également que la dénomination des fonctions pourrait être meilleure / plus idiomatique.then
la promesse originale et accomplir la même chose car elle est de toute façon asynchrone. Il y a un moyen avecprocess.binding('util').getPromiseDetails
cela semble fonctionner mais il utilise une API privée