Basics of Method Chaining in JavaScript using Lodash
Prerequisites: Javascript and soft corner for functional programming
What to expect from this article ?
Performing transformation on an array has been made easy using map
. Sorting an array was never an issue. Picking out first value from array is also trivial. But imagine a situation where in you have to perform all the operation one after other. Basic approach would create intermediate variables and use result of first output as argument for second and so on. This could be frustrating as soon enough you’ll end up having a lot of variables which aren’t used anywhere else.
Method chaining exactly solves this problem and is a much better approach. I would be using Lodash Library for chaining in this article.
Chaining, also known to people as Cascading methods, refers to repeatedly calling one method after another on an object, in one continuous line of code. It allows us to read code like a sentence, flowing gracefully across the page. It also frees us from the monotonous, blocky structures we usually construct.
The best way to understand method chaining or method cascading is to imagine data (object, array or any type of variable) on which a sequence of functions are being applied to achieve the final result.
A point to be noted is that the output of the first should be compatible with the input of second.
Mathematically speaking final result (y) could be achieved by two methods
- Nesting Method
y = f4(f3(f2(f1(x))
2. Cascading Results
x1 = f1(x);
x2 = f2(x1);
x3 = f3(x2);
y = f4(x3);
Consider this example (Quoting from lodash itself):
var users = [
{
"user": "barney",
"age": 36
},
{
"user": "fred",
"age": 40
},
{
"user": "pebbles",
"age": 1
}
]
You want to find the user with least age and display its name and age.
Nested Approach
// youngest = "pebbles is 1"
var youngest = _.head(_.map(_.sortBy(users, 'age'), o=>o.user + ' is ' + o.age));
Chainable Approach
// youngest = "pebbles is 1"
var youngest = _.chain(users).sortBy('age').map(o=>o.user +' is ' + o.age).head().value();
In the nested approach, the code becomes more and more complex to understand as the operations increase.
If you have all the patience in the world, you can go ahead and get the final outcome with nested approach, but even after that if some operation in the middle needs to be edited, it might take a while to think about it and fix it.
Apart from this, chainable approach has several other advantages:
- The execution of chainable sequence is lazy i.e it won’t execute until
.value()
is called. - Lazy evaluation allows several methods to support shortcut fusion. Shortcut fusion is an optimization to merge iteratee calls; this avoids the creation of intermediate arrays and can greatly reduce the number of iteratee executions
- Consider the above given example, but you require one more output, let’s say name and age of the person with maximum age. Using the fact that chainable sequence doesn’t get executed until
.value()
is called, we can do the following:
var chainedTransformer = _.chain(users).sortBy('age').map(o=>o.user + ' is ' + o.age);// youngest = "pebbles is 1"
var youngest = chainedTransformer.head().value();// oldest = "fred is 40"
var oldest = chainedTransformer.reverse().head().value();
Neat and sweet !
Going by the nested method it would have been
// youngest = "pebbles is 1"
var youngest = _.head(_.map(_.sortBy(users, 'age'), o=>o.user + ' is ' + o.age));// oldest = "fred is 40"
var oldest = _.head(_.reverse(_.map(_.sortBy(users, 'age'), o=>o.user + ' is ' + o.age)));
Refer to the list of chainable function in the external refernce given below.
In all those methods where collection
is the first argument in the normal unchained function, it is provided by the output of the previous method.
Example:
_.map(collection, (value, idx/key, collection)=> {
// perform logic
});
Requires first argument as collection but when chained, collection is provided by the previous block’s output, hence only one argument is required in the case of .map()
. Similar could be expected from all other chainable methods too.
Real life scenario:
A bar chart showing comparison of performance of top 5 students in a class needs to be displayed. The backend guy is not friendly and refuses to give you top 5 value in the required format instead sends you data for all the students. So what do you do ?
- Make api call to get the data from backend
- Wrap the response in chain
- Cascade sortBy with marks key
- Cascade reverse since we want top 5
- Cascade slice to get top 5
- Cascade map to do the formatting
- Call
value()
to get the final transformed data
External Reference:- https://lodash.com/docs/4.17.10#chain