Update 10/10/2013 - A good point was made that doing the array creation isn't really going to be different between the libraries. I've modified the find/map/lazy samples to reflect this, and updated the numbers appropriately.

Fast code is fun. And nothing is more fun than making your application faster by dropping in a new library, without spending time re-writing code or spending money on new hardware.

Luckily, there are 2 projects for your next node.js/web app that promise to do just this. lodash.js and lazy.js are both replacements for underscore.js that promise faster performance, as well as some new features.

Lodash is fairly well known for its excellent compatibility with underscore.js. Lazy, on the other hand, should potentially offer even better performance, at the cost of implementing a slightly different API.

 1 Underscore = require('underscore')
 2 Lodash = require('lodash')
 3 Lazy = require('lazy.js')
 4 exports.compare = {
 5   "underscore" : function () {
 6     var array = Underscore.range(1000)
 7   },
 8   "lodash" : function () {
 9     var array = Lodash.range(1000)
10   },
11   "lazy" : function () {
12     var array = Lazy.range(1000).toArray()
13   }
14 };
15 require("bench").runMain()

Running this comparison shows lodash as the winner, underscore close, and lazy way behind. That said, this item is too trivial to really be interesting, and it doesn't really give lazy.js a fair chance to do any lazy evaluation, so lets keep going.

  • lodash - 110.98 operations / ms
  • underscore - 103.60 operations / ms
  • lazy - 28.85 operations /ms
 1 Underscore = require('underscore')
 2 Lodash = require('lodash')
 3 Lazy = require('lazy.js')
 4 var array = Underscore.range(1000)
 5 exports.compare = {
 6   "underscore" : function () {
 7     Underscore.find(array, function(item) {
 8       return item == 500;
 9     })
10   },
11   "lodash" : function () {
12     Lodash.find(array, function(item) {
13       return item == 500;
14     })
15   },
16   "lazy" : function () {
17     Lazy(array).find(function(item) {
18       return item == 500;
19     })
20   }
21 };
22 require("bench").runMain()

And the results

  • WINNER -lazy - 175.65 operations /ms
  • lodash - 168.47 operations / ms
  • underscore - 36.98 operations / ms

Lazy.js is the clear winner here. Lets try another example to see if the setup changes with even more processing.

 1 Underscore = require('underscore')
 2 Lodash = require('lodash')
 3 Lazy = require('lazy.js')
 4 square = function(x) { return x * x; }
 5 inc = function(x) { return x + 1; }
 6 isEven = function(x) { return x % 2 === 0; }
 7 var array = Underscore.range(1000)
 8 exports.compare = {
 9   "underscore" : function () {
10     Underscore.chain(array).map(square).map(inc).filter(isEven).take(5).value()
11   },
12   "lodash" : function () {
13     Lodash.chain(array).map(square).map(inc).filter(isEven).take(5).value()
14   },
15   "lazy" : function () {
16     Lazy(array).map(square).map(inc).filter(isEven).take(5)
17   }
18 };
19 require("bench").runMain()
  • WINNER - lazy - 14375.12 operations /ms
  • lodash - 19.10 operations / ms
  • underscore - 7.17 operations / ms

Full source code is available on github