3

I'm having a speed issue on my Backbone app during the endless scrolling event; models are added to a collection individually, and so the collection is sorted every time. I'm wondering how I can optimize this and have 2 solutions:

  1. Cache them and add them to the collection in bulk, merging 20 sorts into 1
  2. Silently adding the models to the collection, and debouncing the call I make to sort during each add (so only one call is made in the end)

So I'm wondering if 2 is even possible, as it would be easier to implement, and if there is a better solution I'm not thinking of. Thanks!

Garrett
  • 11,451
  • 19
  • 85
  • 126

3 Answers3

1

You can use Collection.reset() to insert multiple elements to your collection and only fire one sort event. The elements added are replaced, so existing elements would need to be merged if they exist.

Rather than caching the items, you could override the add method and call sort yourself, utilizing your debounce approach.

initialize: function() {
   // if you declare the debounce at the Collection.extend(...) level, it will be
   // global to all objects (if you have 20 collections they all have to stop calling
   // sort before this will fire) so putting it here in initialize is probably wise
   this.sort = _.debounce(function(a, b) {
       /* do your mojo */
   }, 250)
},

add: function(m, opts) {
   if( !m instanceof Backbone.Model ) {
      m = new Backbone.Model(m);
   }
   this.models.push(m);
   // probably need to check for opts here and honor silent?
   this.trigger('add', m);
   // for consistency, not sure if this should come before or after the trigger for "add"
   this.sort();
}
Kato
  • 40,352
  • 6
  • 119
  • 149
0

Just to be sure, is your collection sorted automatically because you defined a comparator function?

I tried reading through the Backbone and Underscore source to determine the sorting method used. Unfortunately I couldn't make it out after 10 minutes of reading, so I can't figure out if a low-performance sort method is used. Still, I'm skeptical that the sorting is your major slowdown. In my experience, collection speed issues usually came from views re-rendering from add and update events.

2 is very possible by combining your idea with 1, just add new models to an array and use _.debounce to add the array to the collection every 500 ms. Be sure that the function you pass to debounce also clears out the array.

Eric Hu
  • 18,048
  • 9
  • 51
  • 67
  • 2
    Look inside [`Collection#set`](https://github.com/documentcloud/backbone/blob/master/backbone.js#L726) and [`Collection#sort`](https://github.com/documentcloud/backbone/blob/master/backbone.js#L822). You'll see that it uses the standard `Array#sort` or Underscore's `sortBy` (which is `Array#sort` combined with a Schwartzian Transform) depending on how many arguments the comparator function takes. – mu is too short Jun 14 '13 at 01:56
  • @muistooshort Ahh so that's what Underscore is using. Thanks for sharing the name. Tying this back into the original question, it looks like Array#sort has a [different implementation between browsers, but they're generally chosen to be efficient](http://stackoverflow.com/a/236534/640517). I would not spend time trying to optimize the sorting algorithm here. – Eric Hu Jun 14 '13 at 18:45
  • I'm actually adding them all at the same time, it's just small inefficiencies like sorting on every add vs. once per batch is improving my efficiency by ~10% on mobile web (which I've measured using Safari's web inspector timing). I've already changed the view appending to be batch, so that's not part of the slowdown. – Garrett Jun 14 '13 at 21:00
0

Because I'm using Parse, I had to modify their older version of Backbone to include the options.sort option in the Collection.add function:

      if (this.comparator && options.sort !== false) {
        this.sort({silent: true});
      }

So I'm adding using collection.add(model, {sort:false}) and then calling collection.sort().

However, in my case, I've also realized that sorting is not necessary (as the models are added in sorted order), so I've completely cut out sorting and saved myself ~10% of the time during a batch load in my endless scroller.

Thanks!

Garrett
  • 11,451
  • 19
  • 85
  • 126