Como espero uma promessa terminar antes de retornar a variável de uma função?

149

Ainda estou lutando com promessas, mas fazendo algum progresso graças à comunidade daqui.

Eu tenho uma função JS simples que consulta um banco de dados Parse. Ele deve retornar a matriz de resultados, mas obviamente devido à natureza assíncrona da consulta (daí as promessas), a função retorna antes dos resultados, deixando-me com uma matriz indefinida.

O que preciso fazer para que essa função aguarde o resultado da promessa?

Aqui está o meu código:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    var promise = query.find({
               success: function(results) {
               // results is an array of Parse.Object.
                             console.log(results);
                             //resultsArray = results;
                             return results;
               },

               error: function(error) {
               // error is an instance of Parse.Error.
                             console.log("Error");
               }
    });                           

}
mac_55
fonte
3
Você também pode considerar o uso de async / waitit. Nó agora suporta async / await fora da caixa desde a versão 7.6
Viliam Simko

Respostas:

66

Em vez de retornar um, resultsArrayvocê retorna uma promessa para uma matriz de resultados e, em seguida, thenaquela no site da chamada - isso tem o benefício adicional de o chamador saber que a função está executando E / S assíncrona. A simultaneidade de codificação em JavaScript é baseada nisso - você pode ler esta pergunta para ter uma idéia mais ampla:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    return query.find({});                           

}

// later
resultsByName("Some Name").then(function(results){
    // access results here by chaining to the returned promise
});

Você pode ver mais exemplos de como usar promessas de análise com consultas na postagem do blog do Parse sobre isso .

Benjamin Gruenbaum
fonte
você pode me dizer qual é o suporte disso? IE9 suporta isso?
Sandra-p #
Sim, mas o próprio Parse está quase morto, então existe a @SandrinaPereira. Este é o código da nuvem de análise .
Benjamin Gruenbaum
1
Ah, então isso não é apenas javascript puro? Eu estava procurando uma maneira de fazer isso (espera para uma função para terminar para iniciar outra), mas apenas com javascript puro ..
sandrina-p
A questão é sobre código de análise, não promessas. As promessas podem funcionar (com uma biblioteca) em qualquer navegador. Runs Bluebird em IE6 e Netscape 7.
Benjamin Gruenbaum
1
Estou lendo SO há dois dias e, ainda assim, ninguém resolveu isso. Esta resposta aceita é a mesma que todas as outras. A função retorna uma promessa, não um valor conforme o OP solicitado. Por que esta resposta está marcada como aceita?
IGanja
19

O que preciso fazer para que essa função aguarde o resultado da promessa?

Use async/await(NÃO faz parte do ECMA6, mas está disponível para Chrome, Edge, Firefox e Safari desde o final de 2017, consulte canIuse )
MDN

    async function waitForPromise() {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }

Adicionado devido ao comentário: Uma função assíncrona sempre retorna uma promessa e, no TypeScript, seria semelhante a:

    async function waitForPromise(): Promise<string> {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }
Martin Meeser
fonte
4
A função assíncrona ainda retornará um objeto de promessa se chamado sem aguardar (ou em código não assíncrono). Verifique o resultado do console.log (waitForPromise ()) se tiver dúvidas. Uma verificação de console.log (resultado) dentro da função assíncrona irá imprimir o que você espera, mas o retorno da função assíncrona acontece imediatamente sem bloqueio e retorna uma promessa. Normalmente, o bloqueio de javascript é muito ruim, pois é um aplicativo único e encadeado, causando fome a qualquer outro pub / sub clientes de notificações, essencialmente trazendo o aplicativo inteiro de joelhos.
SRM
1
.net tem .wait () na classe de tarefa "promessa". Javascript está faltando esse recurso? Preciso esperar algo antes de sair da ferramenta de linha de comando do nó, que pode canalizar sua saída para outra ferramenta. "aguardar" funciona apenas dentro de funções assíncronas. Significando que não funciona fora do escopo de uma promessa.
TamusJRoyce
@SRM Eu sinto que o seu comentário se baseia em uma interpretação incorreta da amostra - trata-se da solução Promise "interna" (como o exemplo mais simples da Promise), para que não haja chamadas externas como você afirma no seu comentário. Então, eu decidi atualizar a resposta.
Martin Meeser 7/11
@TamusJRoyce Acho que essa é uma pergunta por si só, mas acho que em C # você pode usar Task.ContinueWith (Task), que é a mesma ideia que você vê na resposta aceita (onde é chamada "then ()").
Martin Meeser 7/11
Eu acho que vejo agora. Eu posso envolver meu script inteiro em uma enorme função assíncrona. E chame essa função como a última linha do meu script. Essa função ainda seria um pouco da placa da caldeira. Mas muito menos do que eu percebi anteriormente. Não estou acostumado a escrever funções dentro de funções. Obrigado @MartinMeeser!
TamusJRoyce
3

Você não deseja que a função aguarde, pois o JavaScript não deve ser bloqueado. Em vez disso, retorne a promessa no final da função, e a função de chamada poderá usar a promessa para obter a resposta do servidor.

var promise = query.find(); 
return promise; 

//Or return query.find(); 
Vestígio
fonte
1
Todo o seu retorno de chamada success:está desativado.
Benjamin Gruenbaum
Ou melhor: return query.find();.
puré de
Também ok. Vou deixar assim para fins ilustrativos, mas adicionei como comentário.
Rastreie
Eu tentei isso, mas os resultados parecem estar indefinidos. resultsByName ("name"). then (function (results) {console.log ("matriz obtida" + resultados.conta);});
mac_55
1
Obrigado, deve ter havido algum tipo de erro na função de resultados. Está funcionando agora. Mudei de console.log para results.length e pode ver que há uma entrada no meu array retornado :)
mac_55
2

Você não está realmente usando promessas aqui. O Parse permite usar retornos de chamada ou promessas; sua escolha.

Para usar promessas, faça o seguinte:

query.find().then(function() {
    console.log("success!");
}, function() {
    console.log("error");
});

Agora, para executar coisas após a conclusão da promessa, você pode executá-lo apenas dentro do retorno de chamada da promessa dentro do then() chamada. Até agora, isso seria exatamente o mesmo que retornos de chamada regulares.

Realmente fazer bom uso das promessas é quando você as encadeia, assim:

query.find().then(function() {
    console.log("success!");

    return new Parse.Query(Obj).get("sOmE_oBjEcT");
}, function() {
    console.log("error");
}).then(function() {
    console.log("success on second callback!");
}, function() {
    console.log("error on second callback");
});
amassar
fonte
Que tipo de objeto é o objeto de resultados? como ele não parece conter minha matriz
mac_55 3/15
Deve ser uma matriz de Parse.Object's.
puré de