Using Underscore.js to improve Sugar 7 performance

If you've browsed the Sugar 7 JavaScript codebase much then you'll notice that we use Underscore.js all over the place. Use of _.each, _.bind, _.debounce, _.filter, and more are littered throughout the Sugar 7 codebase.  It's not uncommon to see multiple usages of it on the same line of code.
 this.resize = _.bind(_.debounce(this.resize, 200), this);

In order to get a quick estimate of how often Underscore is used, you can do a quick search for "_." within JavaScript sources.  The Sugar 7.5 JavaScript codebase turns up 5,976 uses of Underscore.js!

We love Underscore for a couple different reasons.  First off, it helps make our JavaScript code much more readable than if we used vanilla JavaScript everywhere.  Secondly, there's some handy utilities in Underscore that can be expertly applied to improve Sugar 7 application performance.

Read below to learn how several Underscore.js Function utilities can be used to improve performance and responsiveness of your apps.

Lets start with a real example where we used _.debounce() to improve performance for end users of Sugar 7.5.

filter-quicksearch.js

    ({
...

/**
     * Fire quick search
     * @param {Event} e
*/
    throttledSearch: _.debounce(function(e) {
var newSearch = this.$el.val();
if(this.currentSearch !== newSearch) {
this.currentSearch = newSearch;
this.layout.trigger('filter:apply', newSearch);
        }
    }, 400),

...
    })

What debounce does is postpone execution of a function until after an elapsed time has passed since a function was last called.  In this case, the throttledSearch function gets called every time there is a key press in a Sugar 7 Quick Search input box.  Without debounce, if a user was trying to type a search term like "Acme" then we'd be triggering search for "A", "Ac", "Acm", and then "Acme".  This creates a load on the server and gives impression that the search feature isn't working properly because of the delay in displaying the final search results due to all the previous unnecessary requests.

Using _.debounce(fn, 400) means that searches will not be triggered until the user pauses typing for almost half a second (400 milliseconds)._.throttle() is similar except that it triggers the wrapped function at most once for every given time interval.  This makes it useful to implement some sort of rate limiting if you expect many requests to occur faster than they could be reasonably handled._.defer() is my favorite Underscore function.  It allows you to put an operation that doesn't need to be run immediately on the JavaScript event queue where it will be executed later after any pending UI events.  This improves user experience of the app since it shortens long running JavaScript operations that would otherwise block the user interface and make the web app appear unresponsive.  If you want to pop up an informational dialog or re-render a view - do you really need to do it synchronously?  Probably not.  A momentary delay in favor of a responsive user interface is a very good trade-off.

There's a lot more to Underscore than what I've described here.  I hope you take the time to explore it and incorporate usage of it into your Sugar 7 apps and customizations!