2012-12-12 35 views
0

我想在一段时间(从视图中调用)后在我的Backbone集合(“Posts”)中切换状态变量,并尝试使用setTimeout。然而,我认为我搞砸了我的范围,因为我的切换功能不起作用(它被调用,但没有正确改变)。在backbone.js中使用setTimeout时的作用域问题

如果我使用

setTimeout(this.model.collection.toggleReadyToPreloadNewPost, 1000); 

,代码不工作,而如果我用

this.model.collection.toggleReadyToPreloadNewPost(); 

它正确地触发它。我想知道如何解决这个问题?

骨干查看

//ensures namespace is not already taken yet 
wedding.views = wedding.views || {}; 

//each PostView corresponds to a single post container 
//which contains the user name, user comment, and a photo 
wedding.views.PostView = Backbone.View.extend({ 

    tagName: "li", 
    template: "#item-template", 
    className: "hideInitially post", 

    initialize: function() { 
    _.bindAll(this); 
    this.template = _.template($(this.template).html()); 
    }, 

    render: function() { 
    this.preload(); 
    return this; 
    }, 

    //preloads an image and only after it is done, then append 
    preload: function() { 
    var image = new Image(); 
    image.src = this.model.get("src"); 
    this.model.incrementTimesSeen(); 

    //hides the element initially, waits for it to finish preloading, then slides it down 
    //updates lastSeen only after the image is displayed 
    image.onload = $.proxy(function() { 
     var html = this.template({model: this.model.toJSON()}); 

     this.model.setLastSeen(); 

     //shows the image by sliding down; once done, remove the hideInitially class 
     this.$el.hide().append(html).slideDown(); 
     this.$el.removeClass("hideInitially"); 

     setTimeout(this.model.collection.toggleReadyToPreloadNewPost, 1000); 
    }, this); 
    } 

}); 

骨干收集

//check if namespace is already occupied 
wedding.collections = wedding.collections || {}; 

wedding.collections.Posts = Backbone.Collection.extend({ 
    model: wedding.models.Post, 

    initialize: function() { 
    this.readyToPreloadNewPost = 1; 
    }, 

    //toggles "readyToPreloadNewPost" between 1 and 0 
    toggleReadyToPreloadNewPost: function() { 

    this.readyToPreloadNewPost = this.readyToPreloadNewPost ? 0 : 1; 
    }  
}); 

回答

2

当你这样做:

setTimeout(this.model.collection.toggleReadyToPreloadNewPost, 1000); 

你只是递过setTimeout平原绑定toggleReadyToPreloadNewPost功能和setTimeout将其称之为作为一个简单的功能。结果是当setTimeout调用该函数时this将在toggleReadyToPreloadNewPost里面window

您可以通过匿名函数包装一下你的方法调用得到正确的this

var _this = this; 
setTimeout(function() { 
    _this.model.collection.toggleReadyToPreloadNewPost(); 
}, 1000); 

您还可以使用_.bind

setTimeout(
    _(this.model.collection.toggleReadyToPreloadNewPost).bind(this.model.collection), 
    1000 
); 

你也可以使用_.bindAll内收集的initialize到始终将该方法绑定到相应的this

wedding.collections.Posts = Backbone.Collection.extend({ 
    initialize: function() { 
     _.bindAll(this, 'toggleReadyToPreloadNewPost'); 
     //... 
    } 

然后你原来

setTimeout(this.model.collection.toggleReadyToPreloadNewPost, 1000); 

应该做正确的事情。你只想走这条路线,如果你总想要toggleReadyToPreloadNewPost被绑定,我可能会去第一个。

+0

非常感谢您的帮助和解释!这非常有道理! –

+0

只是一个快速的后续问题:我最初在$ .proxy() - >中调用setTimeout,所以这不会导致调用正确的“this”? –

+0

@Dan:'setTimeout($。proxy(...),1000)'应该可以工作,但'$ .proxy(function(){... setTimeout(...)})'不会'this'(通常)是在函数被调用时确定的,'setTimeout'稍后会调用它,但是'$ .proxy'只适用于当你获取函数的引用时,而不是函数被调用时。 –