Jan 28 2014

Optimizing Slow CollectionViews.

In Marionette.js re-rendering large lists while keeping performance high can be difficult.

Marionette abstracts a lot of the hard parts from you; however, there are still several anti-patterns that permeate apps, slowing render times down to a crawl.

Here are a few solutions to speed things up. They are not perfect for all applications, but they have worked well for me in the past.

Case #1: Minimize the work in onRender

itemView onRender jQuery calls when you have multiple rerenders of a collectionView

The client comes to you and asks, on hover of an item in this list, I should see a tooltip with the long title.

A simple task for CollectionViews and ItemViews—or at least it seems.

Assuming an itemView as follows:

class Cat extends Marionette.ItemView
  # ...
  onRender: ->

This is going to give you exactly what you want. However, when your list is large, this is going to significantly slow down your render speed. Why? Because each of your itemViews will execute this code within the addItemView method on the collectionView.

The solution is to pull this UI interaction behavior out of the itemViews and into the collectionView.

class CatList extends Marionette.CollectionView
    onRender: ->

Now the tooltip behavior runs once after all of your items have been rendered.

Case #2: filtering at an itemView level

React to model changes to toggle visibility within a collectionView, without rerendering the entire collection

Filtering is the bane of many developers. Perhaps in your UX when a user syncs with the persistence layer, single models in your collection will change one of their attributes which then will be represented in the UI by hiding the itemView.

Assuming an itemView as follows

class Crayon extends Marionette.ItemView
  # ...
  modelEvents: ->
    change:color: @handleVisibility

  handleVisibility: ->
    if @model.get('color') is "red" then @$el.hide() else @$el.show()

This optimization is handy when you want your collectionView to be a bit dumb and want to let the itemViews determine their own visibility status in the UI.

Case #3: filtering at a collectionView level

Handle view visibility during collectionView rendering, without having to render your entire collection

When you have a large collection and want to display a subset of that list, there are several solutions. You can create a new collection containing the models, or use a backbone plugin to give your collection filter behaviors.

Here is an approach that I use from within the collectionView.

class People extends Marionette.CollectionView
    addItemView: (item) ->
      super if item.shouldBeShown()

This works well because all models hit addItemView before they are rendered; thus you can short-circuit the entire render logic if the model does not pass your render conditions.

Hopefully this helps you on your way to building more performant web applications!

Sam Saccone - @samccone