Eu tenho uma função simplificada que se parece com isso:
function(query) {
myApi.exec('SomeCommand', function(response) {
return response;
});
}
Basicamente, eu quero chamar myApi.exec
, e retornar a resposta que é dada no lambda de retorno de chamada. No entanto, o código acima não funciona e simplesmente retorna imediatamente.
Apenas por uma tentativa muito tola, tentei o abaixo que não funcionou, mas pelo menos você entendeu o que estou tentando alcançar:
function(query) {
var r;
myApi.exec('SomeCommand', function(response) {
r = response;
});
while (!r) {}
return r;
}
Basicamente, qual é uma boa maneira 'node.js / event driven' de fazer isso? Quero que minha função aguarde até que o retorno de chamada seja chamado e retorne o valor que foi passado para ele.
Respostas:
A maneira "bom node.js / event driven" de fazer isso é não esperar .
Como quase todo o resto ao trabalhar com sistemas controlados por eventos como o nó, sua função deve aceitar um parâmetro de retorno de chamada que será chamado quando o cálculo for concluído. O chamador não deve esperar que o valor seja "retornado" no sentido normal, mas sim enviar a rotina que manipulará o valor resultante:
Então você não o usa assim:
Mas assim:
fonte
fs
sync*
métodos). Como tal, acho que ainda é uma pergunta válida. Existe uma boa maneira de conseguir o bloqueio no nó, além da espera ocupada?sync
métodos fazem. (2) Use fibras, github.com/laverdet/node-fibers , (3) Use promessas, por exemplo, a biblioteca Q, (4) Use uma camada fina em cima do javascript, que parece estar bloqueando, mas compila para assíncrona, como maxtaco.github.com/coffee-scriptUma maneira de conseguir isso é agrupar a chamada da API em uma promessa e usá-la
await
para aguardar o resultado.Resultado:
fonte
async/await
. Muitas vezes não preciso disso, por isso não consigo lembrar de como lidar com essa situação. Estou copiando isso para minhas notas / referências pessoais.verifique isso: https://github.com/luciotato/waitfor-ES6
seu código com wait.for: (requer geradores, sinalizador --harmony)
fonte
Se você não quiser usar a chamada de retorno, use o módulo "Q".
Por exemplo:
Para mais informações, consulte: https://github.com/kriskowal/q
fonte
Se você deseja que seja muito simples e fácil, sem bibliotecas sofisticadas, esperar que as funções de retorno de chamada sejam executadas no nó, antes de executar outro código, é assim:
fonte
Nota: Essa resposta provavelmente não deve ser usada no código de produção. É um truque e você deve saber sobre as implicações.
Existe o módulo uvrun (atualizado para as versões mais recentes do Nodejs aqui ) onde você pode executar uma única rodada de loop do loop do evento principal do libuv (que é o loop principal do Nodejs).
Seu código ficaria assim:
(Você pode usar um método alternativo
uvrun.runNoWait()
. Isso pode evitar alguns problemas com o bloqueio, mas requer 100% da CPU.)Observe que essa abordagem invalida todo o objetivo do Nodejs, ou seja, ter tudo assíncrono e sem bloqueio. Além disso, isso pode aumentar muito a profundidade do seu pilha de chamadas, para que você possa acabar com estouros de pilha. Se você executar essa função recursivamente, definitivamente encontrará problemas.
Veja as outras respostas sobre como redesenhar seu código para fazê-lo "corretamente".
Esta solução aqui provavelmente é útil apenas quando você faz testes e esp. deseja ter código sincronizado e serial.
fonte
Desde o nó 4.8.0, você pode usar o recurso do ES6 chamado gerador. Você pode seguir este artigo para obter conceitos mais aprofundados. Mas basicamente você pode usar geradores e promessas para fazer esse trabalho. Estou usando o bluebird para promisificar e gerenciar o gerador.
Seu código deve estar bem, como no exemplo abaixo.
fonte
supondo que você tenha uma função:
você pode usar retornos de chamada como este:
fonte
Isso anula o objetivo de não bloquear IO - você está bloqueando quando não precisa de bloqueio
:)
Você deve aninhar seus retornos de chamada em vez de forçar o node.js a aguardar ou chamar outro retorno de chamada dentro do retorno de chamada em que precisa do resultado
r
.As chances são de que, se você precisar forçar o bloqueio, está pensando em sua arquitetura errada.
fonte
http.get()
algum URL econsole.log()
seu conteúdo. Por que eu tenho que pular para trás para fazer isso no Node?Usar async e aguardar é muito mais fácil.
fonte