Como acessar o valor de uma promessa?

146

Estou vendo este exemplo nos documentos da Angular, $qmas acho que isso provavelmente se aplica às promessas em geral. O exemplo abaixo é copiado literalmente de seus documentos com o comentário incluído:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

// promiseB will be resolved immediately after promiseA is resolved and its value
// will be the result of promiseA incremented by 1

Não estou claro como isso funciona. Se eu puder chamar .then()o resultado do primeiro .then(), encadeando-os, o que eu sei que posso, então promiseBé um objeto de promessa, do tipo Object. Não é um Number. Então, o que eles querem dizer com "seu valor será o resultado da promessaA incrementada em 1"?

Devo acessar isso como promiseB.valueou algo assim? Como o retorno de chamada de sucesso retorna uma promessa E retorna "resultado + 1"? Estou sentindo falta de algo.

temporary_user_name
fonte
Eu fiz uma pergunta relacionada: Por que o Promise não tem uma função get ()?
Roland
1
Isso responde sua pergunta? Como faço para retornar a resposta de uma chamada assíncrona?
Heretic Monkey
Esta pergunta tem 5 anos e tem uma resposta aceita ...
temporary_user_name
@temporary_user_name: não há problema em pessoas votarem a qualquer momento, mesmo em perguntas antigas.
halfer

Respostas:

141

promiseAA thenfunção de retorna uma nova promessa ( promiseB) que é resolvida imediatamente após a promiseAresolução, seu valor é o valor daquilo que é retornado da função de sucesso promiseA.

Nesse caso, promiseAé resolvido com um valor - resulte, em seguida, resolve imediatamente promiseBcom o valor de result + 1.

O acesso ao valor de promiseBé feito da mesma maneira que acessamos o resultado de promiseA.

promiseB.then(function(result) {
    // here you can use the result of promiseB
});

Editar dezembro de 2019 : async/ awaitagora é padrão em JS, o que permite uma sintaxe alternativa à abordagem descrita acima. Agora você pode escrever:

let result = await functionThatReturnsPromiseA();
result = result + 1;

Agora não há promessaB, porque desembrulhamos o resultado do uso da promessaA awaite você pode trabalhar diretamente com ele.

No entanto, awaitsó pode ser usado dentro de uma asyncfunção. Portanto, para diminuir um pouco o zoom acima, o conteúdo acima deveria estar contido da seguinte forma:

async function doSomething() {
    let result = await functionThatReturnsPromiseA();
    return result + 1;
}
Nachshon Schwartz
fonte
2
Promessas são teoricamente seus próprios objetos. eles contêm um resultado que pode ser acessado através da função de sucesso da promessa.
Nachshon Schwartz
2
Portanto, se você deseja trabalhar com o valor de retorno do retorno de chamada assíncrono de uma promessa, isso deve ser feito dentro de outro retorno de chamada assíncrono. Faz sentido. Eu estava procurando uma maneira de obter algum valor de retorno primitivo final, mas acho que isso desafiaria a razão, dado o contexto.
temporary_user_name
2
@Aerovistae, na verdade, o ES6 introduz geradores que tornam isso possível e o ES7 introduz funções assíncronas - que fornecem açúcar de sintaxe sobre promessas que fazem com que pareça código síncrono (executando uma máquina de estado em segundo plano) - então segure firme :)
Benjamin Gruenbaum
25

Quando uma promessa é resolvida / rejeitada, ela chama seu manipulador de sucesso / erro:

var promiseB = promiseA.then(function(result) {
   // do something with result
});

O thenmétodo também retorna uma promessa: promessaB, que será resolvida / rejeitada dependendo do valor de retorno do manipulador de sucesso / erro da promessaA .

Existem três valores possíveis que os manipuladores de sucesso / erro da promessaA podem retornar que afetarão o resultado da promessaB:

1. Return nothing --> PromiseB is resolved immediately, 
   and undefined is passed to the success handler of promiseB
2. Return a value --> PromiseB is resolved immediately,
   and the value is passed to the success handler of promiseB
3. Return a promise --> When resolved, promiseB will be resolved. 
   When rejected, promiseB will be rejected. The value passed to
   the promiseB's then handler will be the result of the promise

Armado com esse entendimento, você pode entender o seguinte:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

A chamada então retorna a promessaB imediatamente. Quando a promessaA for resolvida, ele passará o resultado para o manipulador de sucesso da promessaA. Como o valor de retorno é o resultado da promessaA + 1, o manipulador de sucesso está retornando um valor (opção 2 acima), então a promessaB será resolvida imediatamente e o manipulador de sucesso da promessaB será aprovado no resultado da promessaA + 1.

pixelbits
fonte
4

.thenfunção da promessaB recebe o que é retornado da .thenfunção da promessaA.

aqui a promessaA está retornando é um número, que estará disponível como numberparâmetro na função de sucesso da promessaB. que será incrementado em 1

harishr
fonte
3

Analisar o comentário de maneira um pouco diferente da sua compreensão atual pode ajudar:

// promiseB will be resolved immediately after promiseA is resolved

Isso afirma que promiseBé uma promessa, mas será resolvido imediatamente após a promiseAresolução. Outra maneira de ver isso significa que promiseA.then()retorna uma promessa à qual está atribuído promiseB.

// and its value will be the result of promiseA incremented by 1

Isso significa que o valor que promiseAresolveu é o valor que promiseBreceberá como seu valor successCallback:

promiseB.then(function (val) {
  // val is now promiseA's result + 1
});
Jason Cust
fonte
2

A resposta de pixelbits está correta e você deve sempre usar .then()para acessar o valor de uma promessa no código de produção.

No entanto, existe uma maneira de acessar o valor da promessa diretamente após a resolução, usando a seguinte ligação node.js interna não suportada:

process.binding('util').getPromiseDetails(myPromise)[1]

AVISO: process.binding nunca foi concebido para ser usado fora do nó nodejs e a equipe principal do nodejs está procurando ativamente substituí-lo

https://github.com/nodejs/node/pull/22004 https://github.com/nodejs/node/issues/22064

Zeus Lalkaka
fonte
1

Este exemplo eu acho auto-explicativo. Observe como o aguardador aguarda o resultado e você perde a promessa de ser devolvida.

cryA = crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
Promise {<pending>}
cryB = await crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
{publicKey: CryptoKey, privateKey: CryptoKey}
Mestre James
fonte
Isso deve estar em uma função assíncrona.
Samed
0
promiseA(pram).then(
     result => { 
     //make sure promiseA function allready success and response
     //do something here
}).catch(err => console.log(err)) => {
     // handle error with try catch
}
tomnyson
fonte
1
Embora esse código possa responder à pergunta, fornecer um contexto adicional sobre como e por que resolve o problema melhoraria o valor a longo prazo da resposta.
Alexander
0

Você pode fazer isso facilmente usando um método de espera assíncrona em javascript.

Abaixo está um exemplo de recuperação de um valor da promessa do WebRTC usando um tempo limite.

function await_getipv4(timeout = 1000) {
    var t1 = new Date();
    while(!window.ipv4) {
        var stop = new Date() - t1 >= timeout;
        if(stop) {
            console.error('timeout exceeded for await_getipv4.');
            return false;
        }
    }
    return window.ipv4;
}

function async_getipv4() {
    var ipv4 = null;
    var findIP = new Promise(r=>{var w=window,a=new (w.RTCPeerConnection||w.mozRTCPeerConnection||w.webkitRTCPeerConnection)({iceServers:[]}),b=()=>{};a.createDataChannel("");a.createOffer(c=>a.setLocalDescription(c,b,b),b);a.onicecandidate=c=>{try{c.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g).forEach(r)}catch(e){}}})
    findIP.then(ip => window.ipv4 = ip);
    return await_getipv4();
};

OxFEEDFACE
fonte
É importante executar esse snippet não aqui, mas em um navegador real, acredito que isso se deva ao sandbox.
OxFEEDFACE
0

No nó REPL, para obter uma conexão de banco de dados com o valor de uma promessa, adotei a seguinte abordagem:

let connection
try {
  (async () => {
    connection = await returnsAPromiseResolvingToConnection()
  })()
} catch(err) {
  console.log(err)
}

A linha com awaitnormalmente retornaria uma promessa. Esse código pode ser colado no nó REPL ou, se salvo index.js, pode ser executado no Bash com

node -i -e "$(< index.js)"

que deixa você no Node REPL após executar o script com acesso à variável definida. Para confirmar que a função assíncrona retornou, você pode registrar, connectionpor exemplo, e está pronto para usar a variável. É claro que não seria necessário contar com a função assíncrona sendo resolvida ainda para qualquer código no script fora da função assíncrona.

dmstack
fonte
0

Há uma boa resposta acima e aqui está a versão da função ES6 Arrow

var something = async() => {
   let result = await functionThatReturnsPromiseA();
   return result + 1;
}
roopa l
fonte
0

Sou um aprendiz lento de promessas de javascript, por padrão, todas as funções assíncronas retornam uma promessa, você pode agrupar seu resultado como:

(async () => {
//Optional "await"
  await yourAsyncFunctionOrPromise()
    .then(function (result) {
      return result +1;
    })
    .catch(function (error) {
      return error;
    })()
})

" A expressão de espera faz com que a execução da função assíncrona seja pausada até que uma Promessa seja liquidada (ou seja, cumprida ou rejeitada) e retome a execução da função assíncrona após o cumprimento. Quando retomado, o valor da expressão aguardada é o da Promessa cumprida Se a promessa for rejeitada, a expressão de espera lança o valor rejeitado . "

Leia mais sobre aguardar e prometer no MDN Web Docs

LT-Sites
fonte
-5

Talvez este pequeno exemplo de código TypeScript ajude.

private getAccount(id: Id) : Account {
    let account = Account.empty();
    this.repository.get(id)
        .then(res => account = res)
        .catch(e => Notices.results(e));
    return account;
}

Aqui os repository.get(id)retornos a Promise<Account>. Eu atribuí-lo à variável accountdentro da thendeclaração.

aahoogendoorn
fonte
1
Seu código está retornando a conta antes que a promessa possa ser resolvida e, por isso, é recusada, seu código sempre retorna Account.empty ();
Felype