1

编辑:我想出了我在这里发布的原始 YUI3 问题的答案,但它导致了另一个问题,而不是开始一个新线程,我想我只是在这里添加它。请向下滚动查看新问题(以粗体显示)。

原始问题:我在 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,但这也会产生相同的结果。任何人都可以帮忙吗?我真的很感激!

编辑:我实际上想出了一个解决方案——这是经过数小时尝试大量事情之后的结果,但更多的谷歌搜索有时仍然会产生新的结果/答案(实际上我在这个网站上找到了答案)。

所以显然我的代码正在创建一个竞争条件,我所要做的就是修复它:

setTimeout(function(){ 
    timer_trigger();
}, 1000);

我查看了比赛条件,但我不清楚这对我来说意味着什么,以及对我的代码进行看似微不足道的更改如何解决了我遇到的问题。所以回答了原来的问题,但我想把它变成答案产生的问题。

JavaScript 中的线程是如何工作的,是什么导致了我的竞态条件,以及为什么代码中的微小更改修复了我遇到的错误?

4

2 回答 2

3

问题不是竞争条件。对 setTimeout 的额外调用“修复”您的代码的原因是timer_trigger. timer_from考虑在调用函数时为 1的情况下会发生什么。timer: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);

这会导致在已经设置为 0 的timer_trigger情况下再次调用timer_from,从而允许执行 else 块。

于 2009-12-04T15:05:16.223 回答
2

另请注意

Y.Lang.later(1000, Y, timer_trigger());

立即执行 timer_trigger 并将返回值传递给 Y.Lang.later。你可能是说

Y.Lang.later(1000, Y, timer_trigger);
于 2009-12-04T20:36:36.837 回答