У меня была такая же проблема, и вот что я сделал.
Помощник по обратным вызовам
// The Callbacks module.
//
// A simple way of managing a collection of callbacks
// and executing them at a later point in time, using jQuery's
// `Deferred` object.
//
// Source: https://github.com/derickbailey/backbone.marionette/blob/master/lib/backbone.marionette.js#L1291
define(['jquery'], function($) {
function Callbacks() {
this.deferred = $.Deferred();
this.promise = this.deferred.promise();
}
Callbacks.prototype = {
constructor: Callbacks,
// Add a callback to be executed. Callbacks added here are
// guaranteed to execute, even if they are added after the
// `run` method is called.
add: function(callback, contextOverride) {
this.promise.done(function(context, options) {
if (contextOverride) {
context = contextOverride;
}
callback.call(context, options);
});
},
// Run all registered callbacks with the context specified.
// Additional callbacks can be added after this has been run
// and they will still be executed.
run: function(options, context) {
this.deferred.resolve(context, options);
}
};
return Callbacks;
});
Основная коллекция
В этой коллекции у нас есть 2 важных метода: onReset()
и collectionReset()
. Метод onReset()
должен быть тем, как представления "прослушивают" событие reset коллекции, поскольку он использует промисы.
Метод collectionReset()
выполняется только после запуска события reset коллекции, в этот момент мы считаем коллекцию загруженной и разрешаем все добавленные обратные вызовы.
Это учитывает условия гонки, потому что обратные вызовы были добавлены с использованием метода onReset()
и выполняются, даже если событие было инициировано до добавления обратных вызовов.
Когда вы создаете новую коллекцию и делаете ее наследуемой от этой коллекции, вы должны обязательно добавить опцию reset
при извлечении: (new ExampleCollection()).fetch({ reset: true })
// The Core Collection - other collections inherit from this one.
// Source: http://lostechies.com/derickbailey/2012/02/03/get-a-model-from-a-backbone-collection-without-knowing-if-the-collection-is-loaded
define([
'jquery',
'backbone',
'app/callbacks'
], function($, Backbone, Callbacks) {
var CoreCollection = Backbone.Collection.extend({
constructor: function() {
Backbone.Collection.prototype.constructor.apply(this, [].slice.call(arguments));
this.onResetCallbacks = new Callbacks();
this.on('reset', this.collectionReset, this);
},
// The `onReset` method should be called by views to render collection data
// when the particular collection has been loaded from the server.
onReset: function(callback, contextOverride) {
this.onResetCallbacks.add(callback, contextOverride);
if (this.loaded) {
this.onResetCallbacks.run(this);
}
},
// Since this method is called only on the collection's `reset`
// event, we assume that the collection has been fully loaded.
collectionReset: function() {
if (!this.loaded) {
this.loaded = true;
}
// Execute all the `onResetCallbacks` callbacks.
this.onResetCallbacks.run(this);
}
});
return CoreCollection;
});
Пример просмотра
В представлении примера вы должны сделать следующее:
define([
'jquery',
'backbone',
'handlebars',
],
function($, Backbone, Handlebars) {
var ExampleView = Backbone.View.extend({
id: 'example-view',
template: Handlebars.templates.example,
events: {
},
initialize: function() {
// If it renders a collection from the server.
this.collection = __collection_name__;
this.collection.onReset(function() {
// It's guaranteed to execute.
// No race condition anymore!
// ...
});
}
});
return ExampleView;
});
person
istos
schedule
20.11.2014