Pergunta de condição de corrida JavaScript
-
12-09-2019 - |
Pergunta
EDIT: Eu descobri a resposta para a pergunta original do YUI3 que publiquei aqui, mas levou a outra e, em vez de iniciar um novo tópico, pensei em adicioná -lo aqui. Por favor, role para baixo para a nova pergunta (está em negrito).
Pergunta original: Estou tendo alguns problemas para criar um cronômetro de contagem regressiva JavaScript dentro de uma definição de Yui, meu palpite é algo a ver com o escopo de objeto. Aqui está o meu código:
YUI({combine: true, timeout: 10000}).use("node", function (Y) {
var timer = new function(){};
Y.augment(timer, Y.EventTarget);
timer.on('timer:down', function() {
Y.log('timer down event fired', 'event');
Y.Lang.later(1000, Y, timer_trigger());
});
timer.on('timer:end', function() {
Y.log('timer end event fired', 'event');
});
var timer_from;
function startTimer(seconds){ // start a coundown from seconds to 0
timer_from = seconds;
timer_trigger();
}
function timer_display(){
var mins = Math.floor(timer_from/60);
var secs = timer_from - mins*60;
var secsDisp = secs;
if(secs<10){
secsDisp = '0' + secs;
}
Y.one('#timer').set('innerHTML', mins + ':' + secsDisp);
}
function timer_trigger(){
Y.log('timer from is: '+timer_from);
if(timer_from > 0){
timer_from--;
timer_display();
if(timer_from > 0){
timer.fire('timer:down');
}
} else {
timer.fire('timer:end');
}
}
function initializePage(){
startTimer(900);
}
});
O erro que estou recebendo é que ele não espera os 1000ms como se estivesse pedindo para ligar timer_trigger()
E o Safari finalmente me pergunta se eu quero parar de executar o código. Quando faço alguns segundos após o carregamento da página, o timer já caiu para cerca de 3, 4 minutos. Eu também tentei usar setTimeout
Mas isso também produz o mesmo resultado. Alguém pode ajudar? Eu realmente apreciaria isto!
EDIT: Na verdade, descobri uma solução - isso veio depois de horas tentando toneladas de coisas, mas mais algumas pesquisas no Google às vezes ainda podem produzir novos resultados/respostas (encontrei a resposta em esse site, na realidade).
Então, aparentemente, meu código estava criando uma condição de corrida, e tudo o que eu precisava fazer para consertar é o seguinte:
setTimeout(function(){
timer_trigger();
}, 1000);
Procurei condições de corrida, mas não está claro para mim o que isso significa no meu caso e como a mudança aparentemente trivial no meu código corrigiu o problema que eu estava tendo. Então, a pergunta original respondeu, mas eu gostaria de transformar isso na pergunta que surgiu da resposta.
Como funciona o encadeamento no JavaScript e o que causa minha condição de corrida e por que a menor mudança no código corrigiu o erro que eu tive?
Solução
Observe também isso
Y.Lang.later(1000, Y, timer_trigger());
Executa Timer_trigger imediatamente e passa o valor de retorno para y.lang.later. Você provavelmente quis dizer
Y.Lang.later(1000, Y, timer_trigger);
Outras dicas
O problema não é uma condição de corrida. A razão pela qual a chamada adicional para o Settimeout "FILES" seu código é por causa de uma falha lógica em timer_trigger
. Considere o que acontece no caso onde timer_from
é 1 quando a função é chamada. Nem o timer: para baixo nem o timer: o final será acionado.
function timer_trigger(){
Y.log('timer from is: '+timer_from);
if(timer_from > 0){ // Since timer_from is 1, the if block is entered
timer_from--; // timer_from is 0
timer_display();
if(timer_from > 0){ // This block is not entered, but it has no matching else
timer.fire('timer:down');
}
} else { // The matching if block was entered, so this is not
timer.fire('timer:end');
}
}
Você adicionou este código:
setTimeout(function(){
timer_trigger();
}, 1000);
Isso causa timer_trigger
ser chamado mais uma vez com timer_from
já está definido como 0, permitindo que o bloco elimine seja executado.