Speeding up AngularJS filters

For the past 5 months or so I have been working on an AngularJS event calendar where I work at CitySpark. The calendar uses infinite scrolling to load additional events as the user scrolls down the page as it is embedded on customers sites and allows for large amounts of events to be easily navigatable. One of the difficulties in binding to hundreds of objects with multiple properties being watched by AngularJS is performance. On lower powered devices (Particularly iPhones) we noticed slow performance and a lag in scrolling. After using some of the performance tools in Firefox and not getting anywhere I stumbled upon AngularJS Batarang a Chrome plugin for inspecting and diagnosing AngularJS apps.

AngularJS Dirty checking and Filters

AngularJS performs a dirty check upon all bound objects/properties on each digest cycle which is usually triggered by a user interaction, ajax request or in my case timed frequency as the app has a scrolling image at the top that causes a digest. As many can attest this dirty checking is actually very fast and in my experience not a significant bottle neck even for 1,000 or so bound items on a mobile device. Many of the items displayed however will often use a Filter(should be thought of as a formatter) that will format a date or currency or anything for that matter. When using Batarang and looking at the performance it will show how much time is spent in each watch or filter.

AngularJS Slow ':date' filter

In my case the number one culprit was the date filter as each event used it 3->4 times on each event which means that the filter is called 300->400 times every couple seconds or so. In my case what I ended up doing was using javascript memoization which basically caches the result of a function request with its parameters so that if it is called subsequently using the same parameters it is a simple hash lookup. What I did was create a custom date2 filter that uses memoization to speedup subsequent calls as many of the events occur at the same time. Below is a poor mans memoization but you can swap it out for underscore.js's memoize function if you use that in your project.

app.filter("date2", function () {
       var dateCache = {};
       var dateFormat = getDateFilter();
        return function (date, mask) {
            var result = '';
            if (!dateCache[mask + date]) {
                result = dateFormat(date, mask);
                dateCache[mask + date] = result;
            }
            return dateCache[mask + date + utc];
        };