原始问题: 我在YUI定义中创建一个JavaScript倒计时器有一些问题,我的猜测与对象范围有关。这是我的代码:
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);
}
});
我得到的错误是它没有等待1000毫秒,就像我要求它呼叫timer_trigger()
一样,Safari最终会问我是否要停止运行代码。当我在加载页面几秒钟后,计时器已经下降到大约3,4分钟。
我也试过使用setTimeout
,但也会产生相同的结果。有人可以帮忙吗?我真的很感激!
编辑: 我实际上找到了一个解决方案 - 这是经过几个小时的尝试,但有几次谷歌搜索有时仍会产生新的结果/答案(实际上我在this site找到了答案。)
显然我的代码创造了一个竞争条件,我必须做的就是解决这个问题:
setTimeout(function(){
timer_trigger();
}, 1000);
我查看了竞争条件,但我不清楚在我的情况下它意味着什么,以及对我的代码看似微不足道的改变如何解决了我遇到的问题。所以回答的原始问题,但我想把它变成答案产生的问题。
JavaScript中的线程如何工作以及导致我的竞争条件的原因是什么?为什么代码中的微小更改会修复我的错误?
答案 0 :(得分:3)
问题不是竞争条件。附加调用setTimeout“修复”代码的原因是timer_trigger
中的逻辑缺陷。考虑在调用函数时timer_from
为1的情况下会发生什么。定时器:down和timer:end都不会被触发。
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');
}
}
您添加了以下代码:
setTimeout(function(){
timer_trigger();
}, 1000);
这导致timer_trigger
再次被调用,timer_from
已经设置为0,允许执行else块。
答案 1 :(得分:2)
另请注意
Y.Lang.later(1000, Y, timer_trigger());
立即执行timer_trigger并将返回值传递给Y.Lang.later。你可能意味着
Y.Lang.later(1000, Y, timer_trigger);