Skip to content

Latest commit

 

History

History
110 lines (84 loc) · 7.31 KB

TRADEOFFS.md

File metadata and controls

110 lines (84 loc) · 7.31 KB

Tradeoffs

The most common reaction to Just is why not just use Lodash? Lodash is brilliantly engineered, well maintained and battle tested and there are many reasons to use it. Here I'll try to document (as impartially as possible) the cases where you might want to use Just instead.

Short, simplified answer

  • Use Lodash if it covers an edge case you care about (Lodash is very good at covering edge cases)
  • Use Lodash if your app is going to be processing vast datastructures (100,000+ records) and the runtime performance gains exceed the extra page load lag from the increased JavaScript payload.
  • Use Lodash, Underscore or Ramda if they provide a method that Just doesn't (and there are many).
  • Use Just if you care about JavaScript footprint (and none of the above applies).

Why does JavaScript footprint matter?

Alex Russell puts it better than I could:

We regularly see sites loading more than 500KB of script (compressed). This matters because all script loading delays the metric we value most: Time to Interactive. Sites with this much script are simply inaccessible to a broad swath of the world’s users; statistically, users do not (and will not) wait for these experiences to load. Those that do experience horrendous jank.

JavaScript size is especially critical for mobile web development. As Alex points out, 45% of mobile connections occur over 2G worldwide. 75% of connections occur on either 2G or 3G.

How Big are Just utils?

Just utils nearly all weigh in at a tiny fraction of the size of their Lodash counterparts. They're hand written so they include only essential code. All of them are well under 1kB minfied/gzipped¹.

Assuming you don't want to import the entire Lodash monolith, there are two ways to access individual Lodash modules. You can load submodules directly from the Lodash mono-library:

import camelCase from 'lodash/camelcase'

Alternatively, Lodash Modularized provides a set of dependency-free modules:

import camelCase from 'lodash.camelcase'

Lodash Modularized modules are really modular by name only. They're still dependant on other Lodash functions, the only difference is those dependencies are now inlined within the module. The upshot is Lodash modules share a lot of redundant code and are generally much bigger than they need to be.

Module for module, both Lodash import techniques yield the same size, but if you want to import several Lodash modules the earlier technique becomes more efficient, since common dependencies are ony loaded once.

Check out the Just vs Lodash file size comparisons below. (Please note the disclaimer in the footnote¹)

How Robust are Just utils?

The following Just utils pass all Lodash unit tests for core functionality. The only "fails" are by design, for opinionated behaviors (notably argument coercion) which Just intentionally avoids. These are noted in the table.

Just (size¹) Lodash (Size¹) Differences with Lodash
just-values (127b) values (562b) a
just-omit (80b) omit (2540b) a, l
just-pick (75b) pick (874b) a, l
just-map-values (54b) mapvalues (4470b) a, b, j, k
just-map-keys (57b) mapKeys (4470b) a, b, j, k
just-safe-get (65b) get (1750b) i
just-safe-set (108b) set (1930b) i
just-split (145b) chunk (756b) a, b
just-flatten-it (99b) flattendeep (549b) a
just-tail (48b) tail (111b) a
just-unique (268b) uniq (1650b) a
just-zip-it (173b) zip (517b) a, c
just-compact (84b) compact (53b) a
just-intersect (115b) intersection (361b) a, n, o
just-camel-case (180b) camelCase (2020b) a
just-kebab-case (149b) kebabCase (1720b) a
just-snake-case (149b) snakeCase (1720b) a
just-left-pad (316b) padstart (1190b) a, m
just-right-pad (316b) padEnd (1190b) a, m
just-clamp (116b) clamp (355b) a, g, h
just-range (137b) range (705b) (none)
just-curry (72b) curry (2860b) a, d, e
just-partial-it (98b) partial (2940b) a, f
just-once (78b) once (465b) a

a. Just expects correct argument type, Lodash coerces arguments to expected type
b. Just does not invoke other Lodash utils as part of its implementation
c. Lodash zip returns [] if no arguments, Just requires at least one argument
d. Lodash curry supports _ placeholders. Just expects only just-partial to support such placeholders.
e. Lodash curry can be used as a constructor
f. instances of Lodash partial have a unique instanceof value.
g. Lodash clamp works without a lower bound arg. Just always requires lower and upper bounds.
h. If either bound is NaN, Lodash returns 0, Just returns NaN.
i. just-get and just-set follows dotty for (obj, ['a.b']) style arguments. Lodash uses its own rules.
j. Lodash invokes _.identity when predicate function is nullish
k. Lodash accepts _.property shorthand instead of predicate function.
l. Lodash will flatten arguments to pick and omit. e.g. pick(obj, ['a', 'b'], 'c') becomes pick(obj, 'a', 'b', 'c')
m. When splitting left and right multi-character pads, Lodash truncates from the outside:
padStart('cde', 4, 'ab') yields 'acde'
Just truncates from the inside:
just-left-pad('cde', 4, 'ab') yields 'bcde'
n. Lodash works with just one argument, Just expects two
o. Lodash treats NaN values as equal to one other

In addition, these Just utilities, while lacking the additional features of their Lodash equivalents (noted below), match the feature set / behavior of underscore and other comparable libraries.

Just (size¹) Lodash (size¹) Extra Lodash features
just-truncate (54b) truncate (1510b) a
just-debounce (90b) debounce (797b) b, c, d
just-throttle (76b) throttle (857b) b, c, d
just-merge (142b) merge (4220b) e, f, g
just-clone (157b) clonedeep (3360b) e, f, g

a. In addition to a suffix arg, Lodash truncate accepts a separator expression, which when present is used as the truncation point.
b. Lodash has a leading and trailing option, Just only has a leading option.
c. Lodash cancels delayed calls.
d. Lodash has a flushed method that can be applied to throttles/debounces.
e. Lodash can merge circular references.
f. Just only merges plain objects, regular arrays, functions and primitives. Lodash merges additional non-plain object types.
g. Lodash treats sparse arrays as dense.

What's the deal with no dependencies anyway?

See the original blog post

¹Size data generated by package-size. This is the estimated minified, gzipped size for a standalone module. Actual size will vary depending on app bundle composition.