Eu tenho uma promessa de JavaScript puro (implementação interna ou preenchimento múltiplo):
var promise = new Promise(function (resolve, reject) { /* ... */ });
A partir da especificação , uma promessa pode ser uma das seguintes:
- 'resolvido' e 'resolvido'
- 'resolvido' e 'rejeitado'
- 'pendente'
Eu tenho um caso de uso em que desejo interrogar a Promessa de forma síncrona e determinar:
a promessa está estabelecida?
Nesse caso, a promessa foi resolvida?
Eu sei que posso usar #then()
para agendar o trabalho a ser executado de forma assíncrona depois que o Promise mudar de estado. Eu não estou perguntando como fazer isso.
Esta pergunta é especificamente sobre interrogatório síncrono do estado de uma promessa . Como posso conseguir isso?
javascript
promise
es6-promise
jokeyrhyme
fonte
fonte
var promiseStatus = NEW_PRIVATE("Promise#status");
,PromiseSet
função emSET_PRIVATE(promise, promiseStatus, status);
console.log(Promise.new((resolve, reject) => {})
=>Promise { <pending> }
Respostas:
Não existe uma API de inspeção síncrona para promessas nativas de JavaScript. É impossível fazer isso com promessas nativas. A especificação não especifica esse método.
As bibliotecas do Userland podem fazer isso e, se você estiver direcionando um mecanismo específico (como a v8) e tiver acesso ao código da plataforma (ou seja, você pode escrever o código no núcleo ), poderá usar ferramentas específicas (como símbolos particulares) para conseguir isso . Isso é super específico e não na área do usuário.
fonte
.any
e cometido um erro porque Mark insistiu. Por um lado,Promise.race([])
é uma promessa pendente para sempre (e não um erro), normalmente você deseja a primeira promessa bem-sucedida e não apenas a primeira. Enfim, isso não é realmente relevante para a pergunta - o OP perguntou sobre inspeção síncrona e não sobre.race
e suas muitas deficiências.MakeQueryablePromise(Promise.resolve(3)).isResolved
é falso, mas a promessa é obviamente resolvida. Sem mencionar que a resposta também está usando o termo "resolvido" e "preenchido" incorretamente. Para fazer essa resposta, basta adicionar um.then
manipulador - o que ignora completamente o ponto da inspeção síncrona.promessa-status-assíncrona faz o truque. É assíncrono, mas não costuma
then
esperar a promessa de ser resolvida.fonte
Não, não há API de sincronização, mas aqui está a minha versão do assíncrono
promiseState
(com a ajuda de @Matthijs):fonte
Promise.race([ Promise.resolve(p).then(() => "fulfilled", () => "rejected"), Promise.resolve().then(() => "pending") ]);
Embora isso pareça mais seguro para mim:const t = {}; return Promise.race([p,t]).then(v => v === t ? "pending" : "fulfilled", () => "rejected")
evita a criação de promessas adicionais que persistem enquanto o p original estiver pendente.Você pode fazer uma corrida com Promise.resolve
Não é síncrono, mas acontece agora
Um pequeno script para testar e entender seu significado de forma assíncrona
resultados com atraso (0) (comente o atraso)
e os resultados deste teste com o firefox (o chrome mantém a ordem)
promessaState faça .race e .then: Nível 2
fonte
'a value that p should not return'
, use um símboloSymbol
seria um valor único, portanto, você nunca precisaria adivinhar qual "valor [...] p não deve retornar". No entanto, uma referência a um objeto específico também funcionaria.Você pode usar um hack (feio) no Node.js até que um método nativo seja oferecido:
fonte
Promise.prototype.isPending = function(){ return util.inspect(this).indexOf("<pending>")>-1; }
process.binding('util').getPromiseDetails
Promise.resolve('<pending>')
.no nó, digamos interno não documentado
process.binding('util').getPromiseDetails(promise)
fonte
Atualizado: 2019
O Bluebird.js oferece isso: http://bluebirdjs.com/docs/api/isfulfilled.html
Se você preferir criar seu próprio wrapper, aqui está um bom blog .
Como o JavaScript é de thread único, é difícil encontrar um caso de uso comum o suficiente para justificar colocar isso na especificação. O melhor lugar para saber se uma promessa é resolvida é em .then (). Testar se uma promessa é cumprida criaria um loop de sondagem que provavelmente é a direção errada.
assíncrono / espera é uma construção interessante se você quiser raciocinar código assíncrono de forma síncrona.
Outra chamada útil é Promise.all ()
Quando cheguei a esta resposta, esse é o caso de uso que eu estava procurando.
fonte
Você pode cumprir suas promessas dessa maneira
fonte
.then
sempre executa OP de forma assíncrona que deseja inspecionar uma promessa no mesmo turno não obterá o resultado correto aqui. Nota O OP perguntou especificamente sobre inspeção síncrona e mencionou que eles já sabem sobre inspeção assíncrona.É realmente muito irritante que essa funcionalidade básica esteja ausente. Se você estiver usando o node.js, conheço duas soluções alternativas, nenhuma delas muito bonita. Ambos os trechos abaixo implementam a mesma API:
Não parece haver nenhuma maneira de distinguir os dois últimos estados de promessa usando qualquer um dos truques.
1. Use a API de depuração V8
Este é o mesmo truque que
util.inspect
usa.2. Execute microtarefas de forma síncrona
Isso evita a API de depuração, mas possui algumas semânticas assustadoras, fazendo com que todas as microtasks e
process.nextTick
retornos de chamada pendentes sejam executados de forma síncrona. Ele também tem o efeito colateral de impedir que o erro "rejeição de promessa não tratada" seja acionado para a promessa inspecionada.fonte
process._tickCallback
(ou mesmo% RunMicrotick) - ele irá quebrar as coisas aleatoriamente no seu código. Tentei desesperadamente fazê-lo funcionar (principalmente para temporizadores falsos em funções assíncronas) e nunca foi suficientemente estável do lado do Node. Eu meio que desisti de trabalhar nisso. A API do espelho de depuração V8 é totalmente apropriada aqui.DeprecationWarning: DebugContext has been deprecated and will be removed in a future version.
:( Parece que o V8 o removeuprocess.binding('util').getPromiseDetails( promise )
retornos[ 0, ]
para pendentes,[ 1, value ]
preenchidos e[ 2, value ]
rejeitados.Advertência: Esse método usa elementos internos não documentados do Node.js. e pode ser alterado sem aviso.
No Nó, você pode determinar de forma síncrona o estado de uma promessa usando
process.binding('util').getPromiseDetails(/* promise */);
.Isso retornará:
[0, ]
pendente,[1, /* value */]
cumpridos, ou[2, /* value */]
para rejeitado.Agrupando isso em uma função auxiliar:
fonte
jest
(que é o único lugar em que estou realmente interessado). A função existe, mas sempre parece retornarundefined
. Como descubro o que há de errado?mocha
; nunca tentei com issojest
. Talvez comece uma nova pergunta vinculando aqui e inclua sua versão do Node.js. e também ajest
versão?Promise
que estava usando apenas para testar coisas que deveriam estar acontecendo enquanto umPromise
está pendente, mas achei que, enquanto o que escrevi funcionasse, não haveria necessidade de testar isso. além do que depende dele.o que você pode fazer é usar uma variável para armazenar o estado, definir manualmente o estado para essa variável e verificar essa variável.
é claro, isso significa que você deve ter acesso ao código original da promessa. Caso contrário, você pode fazer:
Minha solução é mais codificada, mas acho que você provavelmente não precisaria fazer isso para todas as promessas que usa.
fonte
A partir do Node.js. versão 8, agora você pode usar o pacote de inspeção inteligente para inspecionar de forma síncrona as promessas nativas (sem hacks perigosos).
fonte
Você pode adicionar um método ao Promise.prototype. Se parece com isso:
Editado: a primeira solução não está funcionando corretamente, como a maioria das respostas aqui. Ele retorna "pendente" até que a função assíncrona ".then" seja chamada, o que não ocorre imediatamente. (O mesmo é sobre soluções usando Promise.race). Minha segunda solução resolve esse problema.
Você pode usá-lo em qualquer promessa. Por exemplo:
Segunda (e correta) solução:
E use-o:
Aviso : Nesta solução, você não precisa usar o operador "novo".
fonte
Aqui está uma versão es6 mais detalhada do QueryablePromise, permitindo a capacidade de encadear e capturar após a primeira resolução e resolver ou rejeitar imediatamente para manter a API consistente com a Promessa nativa.
fonte
await
uso à resposta do @ jib , com prototipagem idiomática.note que esta função assíncrona executa "quase" imediatamente como a função sincronizada (ou, na verdade, pode ser instantaneamente).
fonte
2019:
A maneira mais simples de fazer isso, como eu sei
thenable
, é o invólucro super fino em torno da promessa ou qualquer trabalho assíncrono.fonte
Você pode criar sua própria subclasse, digamos
QueryablePromise
, herdando daPromise
classe disponível nativamente , cujas instâncias teriam umastatus
propriedade disponível que você pode usar para consultar o status dos objetos de promessa de forma síncrona . Uma implementação pode ser vista abaixo ou consulte isso para uma melhor explicação.fonte
fetch
ele retornará uma promessa nativa. Como sua classe ajudaria nisso?const queryableFetch = new QueryablePromise((resolve, reject) => {fetch(/.../).then((data) => resolve(data)) })
:? Ou existe algum problema com isso? : /, err => reject(err)
como um segundo argumentothen
ou ele não propagará erros corretamente (entre os motivos pelos quais é considerado o antipadrão do construtor de promessas ). Porém, não é realmente síncrono (por exemplo, não detecta uma promessa já resolvida), mas talvez seja útil nos casos em que você não controla o chamador e a resposta é necessária imediatamente.Há outra maneira elegante e hacky de verificar se uma promessa ainda está pendente apenas convertendo todo o objeto em string e verificando-o com a ajuda de uma inspeção como esta:
util.inspect(myPromise).includes("pending")
.Testado em Node.js 8,9,10,11,12,13
Aqui está um exemplo completo
Resultado:
fonte
Se você estiver usando o ES7 experimental, poderá usar o assíncrono para cumprir facilmente a promessa que deseja ouvir.
fonte
Eu escrevi um pequeno pacote npm, promessa-valor, que fornece um wrapper de promessa com um
resolved
bandeira:https://www.npmjs.com/package/promise-value
Também fornece acesso síncrono ao valor da promessa (ou erro). Isso não altera o próprio objeto Promise, seguindo o padrão de quebra, em vez de estender.
fonte
Esta é uma pergunta mais antiga, mas eu estava tentando fazer algo semelhante. Eu preciso manter n trabalhadores. Eles estão estruturados em uma promessa. Preciso digitalizar e ver se eles foram resolvidos, rejeitados ou ainda pendentes. Se resolvido, preciso do valor; se rejeitado, faça algo para corrigir o problema ou pendente. Se resolvido ou rejeitado, preciso iniciar outra tarefa para continuar n. Não consigo descobrir uma maneira de fazer isso com Promise.all ou Promise.race, pois continuo trabalhando em uma matriz e não consigo encontrar nenhuma maneira de excluí-las. Então eu crio um trabalhador que faz o truque
Preciso de uma função de gerador de promessas que retorne uma promessa que resolva ou rejeita conforme necessário. É chamado por uma função que configura a estrutura para saber o que a promessa está fazendo.
No código abaixo, o gerador simplesmente retorna uma promessa com base em setTimeout.
Aqui está
doWork retorna um objeto que contém a promessa e seu estado e valor retornado.
O código a seguir executa um loop que testa o estado e cria novos trabalhadores para mantê-lo em três trabalhadores em execução.
Testado em node.js
BTW Não nesta resposta, mas em outras em tópicos semelhantes, eu odeio quando alguém diz "você não entende" ou "não é assim que funciona". Sugerir uma maneira melhor é ótimo. Uma explicação paciente de como as promessas funcionam também seria boa.
fonte
Achei esta solução simples e me permitiu continuar usando promessas nativas, mas adicionei verificações síncronas úteis. Também não precisei puxar uma biblioteca inteira de promessas.
CAVEAT: Isso funciona apenas se houver algum tipo de interrupção no segmento de execução atual para permitir que as promessas sejam executadas ANTES de verificar as construções síncronas. Isso torna isso de utilidade mais limitada do que eu pensava inicialmente - embora ainda seja útil para meu caso de uso (obrigado Benjamin Gruenbaum por apontar isso)
Em https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved que baseou sua resposta em Existe uma maneira de saber se uma promessa do ES6 foi cumprida / rejeitada / resolvida?
fonte
MakeQueryablePromise(Promise.resolve(3)).isResolved
é falso, mas a promessa é obviamente resolvida. Sem mencionar que a resposta também está usando o termo "resolvido" e "preenchido" incorretamente. Para fazer essa resposta, basta adicionar um.then
manipulador - o que ignora completamente o ponto da inspeção síncrona.let wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);
Que, desde que você faça isso, isso funciona muito bem. Mas você precisa entender esse fato para que isso seja útil. Vou atualizar a descrição com essa ressalva. Também concordo que a nomeação de funções poderia ser melhor / mais idiomática.then
cumprir a promessa original e realizar a mesma coisa, já que é assíncrona. Existe uma maneira comprocess.binding('util').getPromiseDetails
que parece trabalho, mas é usando uma API privada