在setTimeout之后,这会丢失上下文

时间:2014-02-27 22:27:22

标签: javascript javascript-events underscore.js

我有一个名为'succeeder'的自制函数,它应该尝试运行一个名为'func'的函数,并且如果它在一段时间后没有尝试再次运行它。

第一次这很好用,当在setTimeout之后第二次调用func时它失败了,这似乎脱离了上下文。

你能想到这个片段中不正确的事吗?

succeeder({
    func : function () {
        !this.dbOpen && this.init();
        return true;
    },
    context : this,
    interval : 2000,
    success : function () { return true;}
});

function succeeder(opts) {
    function run() {        
        try {           
            //_.delay(function(){opts.func();}.bind(opts.context), 2000);
            setTimeout(function(){ return _.bind(opts.func, opts.context)(); }, 2000);
        } catch (e) {
            run(this.opts, this.interval);
        }       
    }
    run();      
};

感谢

1 个答案:

答案 0 :(得分:0)

您的代码不会执行任何类似描述的操作。此描述也不清楚:“如果它[func]失败”是什么意思? func会抛出异常吗?返回false?或者是什么?

没有代码可以检查func的返回值,但func的示例版本返回truetrue返回值的目的是什么?

你有一个try / catch块,这让我怀疑你正在谈论抛出异常的func调用。但是这个try / catch不会捕获func引发的任何异常!

那是因为try / catch正在包装setTimeout调用。但是没有从try / catch块内部调用func。它被称为稍后,当超时触发时,try / catch在那时不再生效。

opts.success功能是什么?它永远不会被使用。

此外,在第一次尝试呼叫func之前,代码总是需要两秒钟的延迟。你想要那个,或者你想要第一个电话是立即的,只有在电话失败并且你重试时才接受延迟?

这是一个工作示例,可以像您所说的那样做。我假设“失败”意味着“抛出异常”,并且您不希望在初始func调用上有任何延迟。

为了测试代码,我使用了一个运行倒计时的func函数,每次抛出一个异常,最后在倒计时到达0时成功。

在调试控制台打开的情况下运行此命令,以便您可以看到console.log()消息:

function Test() {
    this.countdown = 5;

    succeeder({
        func: function () {
            console.log(
                this.constructor.name,
                'countdown:',
                this.countdown
            );
            if( this.countdown-- ) {
                console.log( 'func throwing error' );
                throw new Error( 'fail' );
            }
            console.log( 'func success!' );
        },
        context: this,
        interval: 1000,
        success: function () { return true; }
    });
};

new Test;

function succeeder(opts) {
    var func = _.bind( opts.func, opts.context );
    function run() {
        try {           
            func();
        } catch (e) {
            setTimeout( run, opts.interval );
        }       
    }
    run();      
};