在backbone.js中使用setTimeout时的范围问题

时间:2012-12-12 08:08:50

标签: javascript backbone.js closures

我试图在一段时间后(从视图中调用)在我的Backbone集合(“帖子”)中切换状态变量,并尝试使用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);
  }

});

Backbone Collection

//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;
  }    
});

1 个答案:

答案 0 :(得分:2)

执行此操作时:

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

您只是处理setTimeout普通的未绑定toggleReadyToPreloadNewPost函数,setTimeout将其称为简单函数。结果是thiswindow调用函数时toggleReadyToPreloadNewPost setTimeout {/ 1}}。

您可以通过将方法调用包装在匿名函数中来获得正确的this

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

您还可以使用_.bind

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

您还可以在集合的initialize中使用_.bindAll来始终将该方法绑定到相应的this

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

然后你原来的

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

应该做正确的事。如果你总是希望绑定toggleReadyToPreloadNewPost,你只想走这条路,我可能会选择第一条路线。