Skip to content

Instantly share code, notes, and snippets.

@thebenedict
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thebenedict/a281de5298ea430625ba to your computer and use it in GitHub Desktop.
Save thebenedict/a281de5298ea430625ba to your computer and use it in GitHub Desktop.
Lesson learned: when they say "data binding", they're not kidding.
/*
TLDR: I bound expensive filtering to the template and it
was run too often. After moving filtering to the controller
it's much faster.
*/
/*
So what happened with those slow filters?
I started with debounce like we discussed, but this gave only
a slight performance improvement:
*/
$scope.$watch("queryWord", _.debounce(function (id) {
$scope.$apply(function(){ applyQuery(); })
}, 300));
var applyQuery = function() {
$scope.textQuery.word = $scope.queryWord;
}
/*
here `queryWord` is the ng-model for the search input field,
and `$scope.textQuery.word` is passed to the filter. I realized
that the above code only debounces the input, while in my
template I have lines like:
*/
<span class="nav-counter">{{countWith($parent.prefilteredExceptCharacteristics, 'stove_characteristics', chstic.slug)}}</span>
/*
Anything inside double curly braces is refreshed with every
digest cycle, so `countWith` was being called with each
keypress (and other events!). By interpolating a filter in the
template I was re-filtering my data 10^4 times or more for
each event.
I moved the filtering into the controller (see SO link below),
storing the output of each filter on the scope. Binding the
stored output to the scope, the line above becomes:
*/
<span class="nav-counter">{{chstic.filterCount}}</span>
/*
With a `$scope.$watch()` on the search text
input and checkbox filters, each `filterCount`
is only updated when the search critera change.
Here's the result: http://catalog.cleancookstoves.org/#/stoves
(I know the load speed is still too slow, but that's a
separate issue)
It's fast enough now that debounce isn't necessary, but I
left in a 250ms delay on the text input because I think
it feels better. There's no delay on the check boxes.
Assorted posts I found helpful:
http://www.aaron-gray.com/delaying-the-digest-cycle-in-angularjs/ (front page of Hacker News 9/18/14!)
http://www.sitepoint.com/understanding-angulars-apply-digest/
http://stackoverflow.com/questions/17656397/angular-js-scaling-performance
http://stackoverflow.com/questions/21088845/can-i-debounce-or-throttle-a-watched-input-in-angularjs-using-lodash
http://tech.small-improvements.com/2013/09/10/angularjs-performance-with-large-lists/
http://stackoverflow.com/questions/14302267/how-to-use-a-filter-in-a-controller
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment