问题
I'm currently working on a project that's using .NET MVC on the back end and Backbone (v1.1) with Marionette JS (v1.8.5) on the front end and I am experiencing some performance issues when trying to render a Composite view with 200 results or item views.
I first came across this SO post of a similar issue which helped me get a newer version of marionette (v1.8.5).
Handlebars templates are being used to show a html table with each itemView being wrapped in a tbody (this has a more complex accordion view within it hence tbody being used rather than a more semantic tr)
The Composite view is being initialised and shown in a Marionette region when it's sub app is initialised.
Here's a simplified version of my code.
Activities sub app
'use strict';
App.module('Activities', function(){
this.startWithParent = false;
});
App.addRegions({
RegionActivities: '#region-Activities' // <= this lives in .NET View of project
});
App.Activities.addInitializer(function (options) {
var module = this,
activities = new Collections.Activities();
module.activitiesView = new Views.ActivitiesView({
collection: activities
});
App.RegionActivities.show(module.activitiesView);
activities.fetch();
});
Activities Composite View
'use strict';
Views.ActivitiesView = Backbone.Marionette.CompositeView.extend({
template: Handlebars.templates['activities/activities'],
itemView: Views.ActivityView,
itemViewContainer: '.admin-table--activities', // <= html table that items are appended to
});
Activities Item View
'use strict';
Views.ActivityView = Backbone.Marionette.ItemView.extend({
template: Handlebars.templates['activities/activity'],
tagName: 'tbody'
});
I read the Marionette Docs on the better performing doc fragment
So the performance issue that I'm having is that all 200 items are being appended one at a time and not utilising docFragment buffer. Through debugging I believe this is because the view is being instantiated with an empty Activities collection before the fetch, so Marionette thinks I'm updating the collection and sets the isBuffering to false.
I've also tried instatiating the activitiesView inside the fetch success callback like so;
activities.fetch({
success: function(newCollection) {
module.activitiesView = new Views.ActivitiesView({
collection: newCollection
});
App.RegionActivities.show(module.activitiesView);
}
});
This does append the 200 items to the collections elBuffer (takes about 4 seconds) but then takes another 50 seconds or so before anything is shown on screen. Debugging suggests the onShow method that's triggered by the collection could be causing this delay as it loop through each item one by one.
Have I missed something?
Am I doing everything in the right places?
Is what I'm trying to achieve even possible?
Seems strange to me that this could be so difficult.
Thanks for you time. Tom
Edit
Here are both the composite view and item view templates.
Activities CompositeView template
<table class="admin-table admin-table--accordion admin-table--activities">
<colgroup>
<col width="10%">
<col width="22%">
<col width="23%">
<col width="23%">
<col width="22%">
</colgroup>
<thead>
<tr>
<th>Type</th>
<th>Vessel</th>
<th>Activity</th>
<th>Information</th>
<th>Review Status</th>
</tr>
</thead>
</table>
Activity ItemView template (each wrapped in tbody)
<tr class="table-title">
<td>Col 1 data</td>
<td>Col 2 data</td>
<td>Col 3 data</td>
<td>Col 4 data</td>
<td Col 5 data</td>
</tr>
<tr class="table-content">
<td colspan="5">More info in here...</td>
</tr>
Update
Results from chrome dev tools javascript CPU profile:
Top 3 items all refer to Marionette triggerMethod taking up 80% of CPU.
Full sized image at: http://i.stack.imgur.com/JjT3Z.png
回答1:
The buffer will be used when the collection is reset, so you could try
activities.fetch({reset: true});
The other option is to wait until the fetch is done (using deferreds/promises) before initializing and displaying your view.
来源:https://stackoverflow.com/questions/25375045/compositeview-slow-to-render-items-for-large-result-set-marionette