渲染没有被称为一个api而是另一个

时间:2016-10-31 19:37:50

标签: javascript backbone.js race-condition

我使用下划线模板配置了一个简单的主干模型和视图。完全相同的配置用于两个单独的API。

API 1按预期工作。

要重现此问题,请注释掉API 1的网址并取消注释API 2的网址。

正如您所看到的,我已经对两个api的响应数据进行了规范化,两个api都返回了完全相同的数据结构。但是,不会调用API 2的呈现方法。更奇怪的是,在极少数情况下,渲染会被API 2调用。

我在这里缺少什么?

// Model
var Quote = Backbone.Model.extend({
  // API 1
  //urlRoot: 'http://quotes.stormconsultancy.co.uk/quotes/1.json',
  
  // API 2
  urlRoot: 'http://quotes.rest/qod.json',

  parse: function (data){
    try{
      data = data['contents'].quotes[0];
    }
    catch(e){
    }

    var rd = {author:data.author, quote:data.quote}
    console.log("parsed", typeof rd, rd);
    return rd;
  },
  
  // UPDATE as suggested by cory
  initialize: function() {
    this.on('all', function(eventName) {
      console.log('QuoteModel: ' + eventName);
    });
  }
});

// View
var QuoteView = Backbone.View.extend({
  initialize: function() {
    this.template = _.template($('#quote-template').html());
    this.listenTo(this.model, 'change', this.render);
  },

  render: function(){
    console.log("render", this.model.attributes)
    this.$el.html(this.template(this.model.attributes));
  }
});

var quoteM = new Quote();
quoteM.fetch();

$(document).ready(function() {
	var quoteV = new QuoteView({
		el: $('#quote'),
		model: quoteM
	});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>

<script type="text/html" id="quote-template">
		<p>The author is : <%= author %></p>
		<p>The content is : <%= quote %></p>
</script>

<div id="quote"></div>

2 个答案:

答案 0 :(得分:1)

为Quote模型上的事件添加一些日志记录,您应该能够快速找到问题。

var Quote = Backbone.Model.extend({
    initialize: function() {
        this.on('all', function(eventName) {
            console.debug('QuoteModel: ' + eventName);
        });
    }
});

答案 1 :(得分:1)

您有一个竞争条件,您可以在创建视图之前获取。

因此,如果在文档准备就绪之前完成提取,则在视图开始侦听模型之前触发更改事件。

最简单的解决方案

$(document).ready(function() {
    var quoteM = new Quote();
    var quoteV = new QuoteView({
        el: $('#quote'),
        model: quoteM
    });
    // fetch after
    quoteM.fetch();
});

最佳解决方案

&#13;
&#13;
var API_DOMAIN = "http://quotes.rest/";
// Reusable model
var Quote = Backbone.Model.extend({});

// reusable quotes collection
var QuoteCollection = Backbone.Collection.extend({
  model: Quote,
  // simple generic parse
  parse: function(response) {
    return response.contents.quotes;
  },
});

// View
var QuoteView = Backbone.View.extend({
  // GOOD: gets called once
  template: _.template($('#quote-template').html()),
  
  initialize: function() {
    // BAD: gets called for every view
    // this.template = _.template($('#quote-template').html());
    
    this.listenTo(this.model, 'change', this.render);
  },

  render: function() {
    console.log("render", this.model.attributes)
    this.$el.html(this.template(this.model.toJSON()));
    // Backbone standard for chaining
    return this;
  }
});


$(function() {
  var quoteV,
    collection = new QuoteCollection();
  collection.fetch({
    url: API_DOMAIN + 'qod.json',
    success: function(collection, response, options) {
      // only create the view when you need it
      quoteV = new QuoteView({
        el: $('#quote'),
        model: collection.first()
      });
      
      // manually render to be 100% in control. The event now only
      // serves if the model really changes.
      quoteV.render();
    }
  });

});
&#13;
<div id="quote"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>

<script type="text/html" id="quote-template">
  <p>The author is :
    <%= author %>
  </p>
  <p>The content is :
    <%= quote %>
  </p>
</script>
&#13;
&#13;
&#13;