Pergunta

Eu tenho um aplicativo da web onde há um cronômetro que está constantemente contando. Enquanto isso, o cliente freqüentemente verifica com o servidor para ver se mais tempo foi adicionado ao timer. O código se parece com o seguinte:

function tick() {
    // This function is called once every second
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    time = newtime;
};

É, é claro, um pouco mais complexo que isso, mas você pode ver a condição de raça inerente. E se a atualização e a função de carrapato estiverem tentando modificar time ao mesmo tempo?

Francamente, não sei JavaScript suficientes para entender como lidar com esse tipo de questão de simultaneidade: existe uma maneira fácil de fazer isso, ou se não, alguém pode me apontar para recursos onde posso aprender mais?

Obrigada.

Foi útil?

Solução

Você não tem uma condição de corrida, porque o JavaScript não é executado simultaneamente.

Toda vez que um retorno de chamada é demitido de uma operação assíncrona (Ajax, setTimeout, etc), esse retorno de chamada deve terminar de executar antes que outro retorno de chamada de outra operação assíncrona possa ser chamado. Então se update() está em execução, nenhum outro javascript é. Uma vez update() Acabamentos, outros retornos de chamada das operações assínconais podem ser demitidos (por exemplo, tick()). Curiosamente, é também por isso setTimeout E sua série não é garantida para executar no momento exato em que o tempo limite é alcançado: algum outro JavaScript pode estar bloqueando a execução do retorno de chamada.

Verificação de saída http://ejohn.org/blog/how-javascript-timers-work/ Para obter boas informações sobre como tudo isso funciona.

Outras dicas

JavaScript é um único rosqueado. Não há condição de corrida. Não há como JavaScript para as duas linhas time = newtime; e time -= 1; para se sobrepor durante a execução. De fato, as duas funções são garantidas para não se sobrepor. Um deles será executado e o outro será executado.

Eu estava errado: isso não resolve o problema! (Explicação após o código)

NEWTIME = false;
function tick() {
    // This function is called once every second
    if (NEWTIME) {
        time = NEWTIME;
        NEWTIME = false;
    }
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    NEWTIME = newtime;
};

O problema com esta solução errada é que fazer dessa maneira você apenas move o problema da condição de corrida da variável time para variável NEWTIME.

Apenas pense o seguinte: a execução de tick alcança e executa a linha time = NEWTIME; Agora, antes de continuar, a atualização é chamada e NEWTIME recebe um valor X. Agora a execução do carrapato continua executando NEWTIME = false;. Dessa forma, você perdeu o X valor de NEWTIME E assim, o efeito de uma atualização () ligue!

O problema precisa de alguns semáforos. Faço muito isso por enviar Ajax após o acabamento anterior. Seu caso é um pouco parecido;)

Experimente algo assim. Deve ignorar todas as tentativas de diminuir o tempo que colide com o retorno de chamada do Ajax.

window.TimeKeeper = new function(){
this.time=0; //initial value, whatever
this.isopen=true;

this.decrement = function(){ 
 if(this.isopen){
  this.time--;
  redisplay(this.time);
  }
 }
this.set = function(val){
 if(this.isopen){
  this.isopen=false;
  this.time=val;
  this.isopen=true;
  } else {
  //another AJAX callback is modifying time. 
   //You can enqueue current value and put it later
  }
 }

}

function tick() {
    TimeKeeper.decrement();

};
function update(newtime) {
    TimeKeeper.set(newtime);
};

Mais uma coisa - o Settimeout funciona como um novo thread e eu esperaria que os navegadores façam o acesso ao MEM sincronizador, por isso pode ser suficiente verificar se o valor não cresceu antes da diminuição. Mas a solução acima é mais flexível e segura.

E uma pequena dica - evite a consulta com o Ajax com muita frequência - pode causar problemas extras - como solicitações que voltam em ordem diferente da enviada e o uso da memória do Firefox aumentando muito o Ajax por um minuto;)

Contanto que você adicione mais alguns segundos à sua hora atual, você deve ficar bem.

Em vez de fazer time = newtime; tentar time += newtime; Dessa forma, você não perderá o segundo em que está preocupado.

Ainda assim, você está perdendo apenas um segundo na pior das hipóteses.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top