Eu tenho uma função javascript como esta:
function myFunction(number) {
var x=number;
...
... more initializations
//here need to wait until flag==true
while(flag==false)
{}
...
... do something
}
O problema é que o javascript travou no momento e travou meu programa. então minha pergunta é como posso esperar no meio da função até que o sinalizador seja verdadeiro sem "espera-ocupado"?
javascript
synchronization
ilay zeidman
fonte
fonte
jQuery.Deferred
,Q
,async
, ...Respostas:
Como o javascript em um navegador tem um único thread (exceto para webworkers que não estão envolvidos aqui) e um thread de execução do javascript é executado até a conclusão antes que outro possa ser executado, sua declaração:
será simplesmente executado para sempre (ou até que o navegador reclame sobre um loop de javascript não responsivo), a página parecerá estar travada e nenhum outro javascript terá a chance de ser executado, portanto, o valor do sinalizador nunca poderá ser alterado.
Para um pouco mais de explicação, Javascript é uma linguagem orientada a eventos . Isso significa que ele executa um fragmento de Javascript até retornar o controle ao interpretador. Então, somente quando retorna ao interpretador, Javascript obtém o próximo evento da fila de eventos e o executa.
Todas as coisas, como temporizadores e eventos de rede, passam pela fila de eventos. Portanto, quando um cronômetro dispara ou chega uma solicitação de rede, ele nunca "interrompe" o Javascript em execução no momento. Em vez disso, um evento é colocado na fila de eventos Javascript e, em seguida, quando o Javascript atualmente em execução termina, o próximo evento é retirado da fila de eventos e chega a sua vez de ser executado.
Portanto, quando você faz um loop infinito como
while(flag==false) {}
, o Javascript em execução no momento nunca termina e, portanto, o próximo evento nunca é retirado da fila de eventos e, portanto, o valor deflag
nunca é alterado. A chave aqui é que o Javascript não é conduzido por interrupções . Quando um cronômetro dispara, ele não interrompe o Javascript em execução no momento, execute algum outro Javascript e, em seguida, deixe o Javascript em execução continuar. Ele apenas é colocado na fila de eventos esperando até que o Javascript atualmente em execução esteja pronto para ser executado.O que você precisa fazer é repensar como seu código funciona e encontrar uma maneira diferente de acionar qualquer código que você deseja executar, quando o será executado no momento certo. Isso é muito, muito mais eficiente do que tentar usar algum tipo de cronômetro para verificar constantemente o valor do sinalizador.
flag
valor mudar. Javascript é projetado como uma linguagem orientada a eventos. Então, o que você precisa fazer é descobrir em quais eventos você pode registrar um interesse para que possa ouvir o evento que pode causar a mudança do sinalizador e pode examinar o sinalizador nesse evento ou pode acionar seu próprio evento de qualquer código pode alterar o sinalizador ou você pode implementar uma função de retorno de chamada para que qualquer código que altere esse sinalizador possa chamar seu retorno de chamada sempre que o trecho de código responsável por alterar o valor do sinalizador altere seu valor paratrue
, ele apenas chama a função de retorno de chamada e, portanto, seu código que quer ser executado quando o sinalizador for definido paratrue
fonte
Javascript é de thread único, daí o comportamento de bloqueio de página. Você pode usar a abordagem adiada / promessa sugerida por outros, mas a forma mais básica seria usar
window.setTimeout
. Por exemploAqui está um bom tutorial com mais explicações: Tutorial
EDITAR
Como outros apontaram, a melhor maneira seria reestruturar seu código para usar callbacks. No entanto, esta resposta deve dar uma ideia de como você pode 'simular' um comportamento assíncrono com
window.setTimeout
.fonte
Usar:
fonte
Solução usando Promise , async \ await e EventEmitter que permite reagir imediatamente na mudança de sinalização sem qualquer tipo de loops.
EventEmitter
está embutido no nó. No navegador, você deve incluí-lo por conta própria, por exemplo, usando este pacote: https://www.npmjs.com/package/eventemitter3fonte
ES6 com Async / Await,
fonte
Com Ecma Script 2017 você pode usar async-await e while juntos para fazer isso E o while não irá travar ou travar o programa, mesmo a variável nunca será verdadeira
fonte
Solução moderna usando Promise
myFunction()
na questão original pode ser modificado da seguinte formaonde
until()
está essa função de utilidadeAlgumas referências às funções async / await e arrow estão em uma postagem semelhante: https://stackoverflow.com/a/52652681/209794
fonte
Para iterar sobre objetos ($ .each) e executar uma operação de longa duração (contendo chamadas de sincronização ajax aninhadas) em cada objeto:
Eu primeiro defini uma
done=false
propriedade customizada em cada um.Então, em uma função recursiva, configure cada um
done=true
e continue usandosetTimeout
. (É uma operação destinada a interromper todas as outras IU, mostrar uma barra de progresso e bloquear todos os outros usos, então me perdoei pelas chamadas de sincronização.)fonte
Semelhante à resposta do Lightbeard, eu uso a seguinte abordagem
fonte
Tentei usar a abordagem @Kiran como segue:
(framework que estou usando me força a definir funções desta forma). Mas sem sucesso porque quando a execução vem dentro da função checkFlag pela segunda vez,
this
não é meu objeto, éWindow
. Então, terminei com o código abaixofonte
usando JavaScript sem bloqueio com API EventTarget
No meu exemplo, preciso aguardar um retorno de chamada antes de usá-lo. Não tenho ideia de quando esse retorno de chamada está definido. Pode ser antes ou depois de eu precisar executá-lo. E posso precisar chamá-lo várias vezes (tudo assíncrono)
fonte
existe um pacote de nós
delay
muito fácil de usarfonte
Adotei uma abordagem semelhante às soluções de retorno de chamada aqui, mas tentei torná-la um pouco mais genérica. A ideia é adicionar funções que você precisa executar depois que algo muda em uma fila. Quando a coisa acontece, você faz um loop pela fila, chama as funções e esvazia a fila.
Adicionar função à fila:
Execute e libere a fila:
E quando você invocar _addToQueue, você desejará envolver o retorno de chamada:
Quando você cumprir a condição, ligue
_runQueue()
Isso foi útil para mim porque tinha várias coisas que precisavam esperar na mesma condição. E separa a detecção da condição de tudo o que precisa ser executado quando essa condição é atingida.
fonte
fonte
No meu exemplo, eu registro um novo valor de contador a cada segundo:
fonte
Se você tiver permissão para usar:
async/await
em seu código, poderá tentar este:Demonstração aqui: https://stackblitz.com/edit/typescript-bgtnhj?file=index.ts
No console, basta copiar / colar:
goahead = true
.fonte