Javascript竞争条件问题

时间:2009-12-04 06:00:37

标签: javascript javascript-events yui settimeout race-condition

编辑:我想出了我在这里发布的原始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,但也会产生相同的结果。有人可以帮忙吗?我真的很感激!

编辑: 我实际上找到了一个解决方案 - 这是经过几个小时的尝试,但有几次谷歌搜索有时仍会产生新的结果/答案(实际上我在this site找到了答案。)

显然我的代码创造了一个竞争条件,我必须做的就是解决这个问题:

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

我查看了竞争条件,但我不清楚在我的情况下它意味着什么,以及对我的代码看似微不足道的改变如何解决了我遇到的问题。所以回答的原始问题,但我想把它变成答案产生的问题。

JavaScript中的线程如何工作以及导致我的竞争条件的原因是什么?为什么代码中的微小更改会修复我的错误?

2 个答案:

答案 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);