使用与骨干的承诺

时间:2014-06-10 15:54:30

标签: jquery backbone.js

我正在尝试做一些可能无法完成的事情,但实际上我正在尝试收集数据然后将其全部传递给视图,但我认为承诺的方式是不可能的。

所以我拥有的是:

  create: function() {
    $('#blog-manage').empty();
    var options = {reset: true};
    var getTags = new AisisWriter.Collections.Tags({per: 9999});

    getTags.fetch(options).then(function(data){
      this.tags = data.tags //=> this.tags is a class level variable. data.tags = array of 5 objects.
    }, this);

    console.log(this.tags) //=> null
    var createPost = new AisisWriter.Views.CreatePost({tags: this.tags });
    createPost.render();
  },

我无法弄清楚为什么在promise中可以将data.tags分配给this.tags但是this.tags的一边是null。我已将this绑定到回调函数。

2 个答案:

答案 0 :(得分:3)

除非您在调用console.log(this.tags)时将AJAX选项更改为同步,否则可能尚未设置this.tags。您可以尝试将此日志语句和createPost移动到promise回调中,如下所示。

create: function() { 
    $('#blog-manage').empty();
    var options = {reset: true};
    var getTags = new AisisWriter.Collections.Tags({per: 9999});

    getTags.fetch(options).then(function(data){
      this.tags = data.tags;  

      // move this logic inside the promise callback or put in a function
      // to call when callback has completed 
      console.log(this.tags) //=> null 
      var createPost = new AisisWriter.Views.CreatePost({tags: this.tags });
      createPost.render();
    }, this); 
},

作为对我的第一个回复的编辑,我创建了一个jsfiddle,展示了如何在不将承诺链接在一起并变得“混乱”的情况下处理这个问题。这可以在视图级别本身处理。您允许视图处理如何处理promise。这允许您分离视图逻辑并允许它处理其模型/集合更改时要执行的操作,即重新呈现自身。以下是jsfiddle中的一些JavaScript,请查看完整的JavaScript和HTML。

AisisWriter.Views.CreatePost = Backbone.View.extend({
    template: _.template($("#tags-template").html()),

    el: "#blog-manage", 

    initialize: function () {
        // anytime our collection changes re-render view 
        // you can also use promise callback to call render
        // OPTION 1 
        this.listenTo(this.collection, "add", this.render);
        this.listenTo(this.collection, "remove", this.render);

        // make the AJAX call to fetch items in our collection 
        // since backbone loads the collection for us we don't 
        // need the promise to assign data  
        // but you could attach the promise here
        // but is completely optional 
        this.collection.fetch(this.options.ajaxOptions)
            .then(_.bind(this.onFetchComplete, this)); // promise is optional    
        // OPTION 2 
        // .then(_bind(this.render, this)); // alternative

    },

    render: function () { 

        // wrap with tags to match how was in stack overflow post 
        var data = {
            tags: this.collection.toJSON()
        };

        this.$el.html(this.template(data));

        return this;
    },

    onFetchComplete: function (data) {
        // .. do something with data...
        // this is not needed though since Backbone
        // will have placed data in collection 
        // this is only here to show you can do something else
        // with the callback if you so desire 

        console.log('fetch of async data complete');

        // sample data just for demo
        // Backbone will have already populated the object 
        // you will notice b/c we used /echo/json as URL
        // of collection it added an empty object
        // since that is what jsfiddle sent back 
        this.collection.add([{
            title: 'foo',
            text: 'text of the post goes here'
        }, {
            title: 'bar',
            text: 'text of this post goes here'
        }]);

        // alternatively you could call render manually
        // instead of using listenTo in initialize method 
        // OPTION 3 
        // this.render(); 
    }
});

答案 1 :(得分:3)

这里发生了几件事:

getTags.fetch(options).then(function(data){
      this.tags = data.tags //=> this.tags is a class level variable. data.tags = array of 5 objects.
    }, this);

由于JavaScript是异步的,因此在返回请求之前,将执行此操作之前或之后的任何操作。返回请求后,将履行承诺,但console.log已经发生。

你的承诺回调中还有一个上下文切换 - 这意味着this不再引用你的想法。虽然你说它已经绑定了,但你的功能是匿名的,所以它不是。我猜测的是你希望this引用outter类。所以要修复它,使代码类似于:

var _this = this; // maintain a reference to your class instance
getTags.fetch(options).then(function(data){
    _this.tags = data.tags;
    console.log(_this.tags)
    // do your rendering
}, this);