Primeiro, este é um caso muito específico de fazê-lo da maneira errada com o objetivo de adaptar uma chamada assíncrona em uma base de código muito síncrona com milhares de linhas e o tempo atualmente não oferece a capacidade de fazer as alterações " certo. " Dói todas as fibras do meu ser, mas a realidade e os ideais geralmente não se misturam. Eu sei que isso é péssimo.
OK, fora do caminho, como faço para que eu possa:
function doSomething() {
var data;
function callBack(d) {
data = d;
}
myAsynchronousCall(param1, callBack);
// block here and return data when the callback is finished
return data;
}
Os exemplos (ou a falta deles) usam bibliotecas e / ou compiladores, os quais não são viáveis para esta solução. Eu preciso de um exemplo concreto de como fazê-lo bloquear (por exemplo, NÃO deixe a função doSomething até que o retorno de chamada seja chamado) SEM congelar a interface do usuário. Se tal coisa é possível em JS.
fonte
Respostas:
ESTÁ BEM. mas você realmente deve fazê-lo da maneira certa ... ou o que quer
Não, é impossível bloquear o JavaScript em execução sem bloquear a interface do usuário.
Dada a falta de informações, é difícil oferecer uma solução, mas uma opção pode ser a função de chamada fazer alguma pesquisa para verificar uma variável global e definir o retorno de chamada
data
como global.Tudo isso pressupõe que você pode modificar
doSomething()
. Não sei se isso está nos cartões.Se puder ser modificado, não sei por que você não passaria apenas um retorno de chamada
doSomething()
para ser chamado pelo outro retorno de chamada, mas é melhor parar antes que eu tenha problemas. ;)Oh, que diabos. Você deu um exemplo que sugere que isso pode ser feito corretamente, então eu vou mostrar essa solução ...
Como seu exemplo inclui um retorno de chamada que é passado para a chamada assíncrona, o caminho certo seria passar uma função
doSomething()
a ser invocada a partir do retorno de chamada.Claro que, se essa é a única coisa que o retorno de chamada está fazendo, você passaria
func
diretamente ...fonte
callback
função para amyAsynchronousCall
função, que faz coisas assíncronas e chama o retorno de chamada quando concluída. Aqui está uma demonstração.As funções assíncronas , um recurso do ES2017 , fazem o código assíncrono parecer sincronizado usando promessas (uma forma específica de código assíncrono) e a
await
palavra - chave. Observe também nos exemplos de código abaixo da palavra-chaveasync
na frente dafunction
palavra - chave que significa uma função assíncrona / aguardada. Aawait
palavra-chave não funcionará sem estar em uma função pré-fixada com aasync
palavra - chave. Como atualmente não há nenhuma exceção a isso, significa que nenhum nível superior de espera funcionará (nível superior aguarda, o que significa uma espera fora de qualquer função). Embora exista uma proposta de nível superiorawait
.O ES2017 foi ratificado (ou seja, finalizado) como padrão para JavaScript em 27 de junho de 2017. O Async aguardar já pode funcionar no seu navegador, mas, se não, você ainda pode usar a funcionalidade usando um transpilador javascript, como babel ou traceur . O Chrome 55 oferece suporte total às funções assíncronas. Portanto, se você tiver um navegador mais novo, poderá experimentar o código abaixo.
Consulte a tabela de compatibilidade es2017 da kangax para obter compatibilidade com o navegador.
Aqui está um exemplo de função de espera assíncrona chamada,
doAsync
que realiza três pausas de um segundo e imprime a diferença horária após cada pausa a partir da hora de início:Quando a palavra-chave wait for colocada antes de um valor prometido (nesse caso, o valor prometido é o valor retornado pela função doSomethingAsync), a palavra-chave wait aguardará a execução da chamada da função, mas não pausará nenhuma outra função e continuará executando outro código até que a promessa seja resolvida. Depois que a promessa for resolvida, ela desembrulhará o valor da promessa e você poderá pensar na expressão de espera e promessa como sendo substituída agora por esse valor desembrulhado.
Portanto, uma vez que wait apenas pausa, espera e, em seguida, desembrulha um valor antes de executar o restante da linha, você pode usá-lo para loops e chamadas de funções internas, como no exemplo abaixo, que coleta diferenças de tempo esperadas em uma matriz e imprime a matriz.
A própria função assíncrona retorna uma promessa para que você possa usá-la como encadeamento, como eu faço acima ou dentro de outra função de espera assíncrona.
A função acima aguardaria cada resposta antes de enviar outra solicitação, se você quiser enviar as solicitações simultaneamente, pode usar Promise.all .
Se a promessa possivelmente rejeitar, você pode envolvê-la em uma tentativa de captura ou pular a tentativa de captura e deixar o erro se propagar para a chamada de captura de funções assíncronas / aguardadas. Você deve ter cuidado para não deixar erros de promessa sem tratamento, especialmente no Node.js. Abaixo estão alguns exemplos que mostram como os erros funcionam.
Se você for aqui, poderá ver as propostas finalizadas para as próximas versões do ECMAScript.
Uma alternativa a isso que pode ser usada apenas com o ES2015 (ES6) é usar uma função especial que envolve uma função de gerador. As funções do gerador têm uma palavra-chave yield que pode ser usada para replicar a palavra-chave wait com uma função circundante. A palavra-chave yield e a função de gerador são muito mais genéricas e podem fazer muito mais coisas do que a função de espera assíncrona. Se você quer um invólucro função de gerador que pode ser usado para assíncrono replicar esperam que eu gostaria check-out co.js . A propósito, as funções co, assim como as funções de espera assíncrona, retornam uma promessa. Honestamente, neste ponto, a compatibilidade do navegador é praticamente a mesma para as funções de gerador e funções assíncronas; portanto, se você deseja apenas a funcionalidade de espera assíncrona, deve usar as funções assíncronas sem co.js.
Atualmente, o suporte ao navegador é muito bom para as funções Async (a partir de 2017) em todos os principais navegadores atuais (Chrome, Safari e Edge), exceto no IE.
fonte
Dê uma olhada no JQuery Promises:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
Refatore o código:
fonte
dfd.notify(data)
paradfd.resolve(data)
Há uma boa solução alternativa em http://taskjs.org/
Ele usa geradores que são novos no javascript. Portanto, atualmente não é implementado pela maioria dos navegadores. Eu testei no firefox, e para mim é uma boa maneira de quebrar a função assíncrona.
Aqui está o código de exemplo do projeto GitHub
fonte
Você pode forçar o JavaScript assíncrono no NodeJS a ser síncrono com o sync-rpc .
Definitivamente, irá congelar sua interface do usuário, por isso ainda sou um pessimista quando se trata do que é possível usar o atalho necessário. Não é possível suspender o thread único e único em JavaScript, mesmo que o NodeJS permita que você o bloqueie às vezes. Nenhum retorno de chamada, evento ou qualquer coisa assíncrona poderá processar até que sua promessa seja resolvida. Portanto, a menos que o leitor tenha uma situação inevitável como o OP (ou, no meu caso, esteja escrevendo um script de shell glorificado sem retornos de chamada, eventos etc.), NÃO FAÇA ISSO!
Mas aqui está como você pode fazer isso:
./calling-file.js
./my-asynchronous-call.js
LIMITAÇÕES:
Ambos são uma consequência de como
sync-rpc
é implementado, que é abusarrequire('child_process').spawnSync
:JSON.stringify
, para que funções e propriedades não enumeráveis, como cadeias de protótipos, sejam perdidas.fonte
Você também pode convertê-lo em retornos de chamada.
fonte
O que você quer é realmente possível agora. Se você pode executar o código assíncrono em um trabalhador de serviço e o código síncrono em um trabalhador da Web, pode pedir ao trabalhador da Web que envie um XHR síncrono ao trabalhador de serviço e, enquanto o trabalhador de serviço faz as coisas assíncronas, o trabalhador da Web thread vai esperar. Esta não é uma ótima abordagem, mas poderia funcionar.
fonte
A idéia que você espera alcançar pode ser possível se você ajustar um pouco o requisito
O código abaixo é possível se o seu tempo de execução suportar a especificação ES6.
Mais sobre funções assíncronas
fonte
SyntaxError: await is only valid in async functions and async generators
. Sem mencionar que o param1 não está definido (e nem usado).