Reputation: 658
const compose = (f, g) => (...args) => f(g(...args));
const bigTask = (...fns) => fns.reduce(compose);
bigTask(
task1,
task2,
task3,
task4
)(user, {data:'data'})
my understanding is the function reduce first picks task1 and task2 and then passes them to compose. The result of the above and task3 is picked as the next arguments to the compose function. The individual tasks: task1, task2... are not dependent on each other so it's not a recursive functions. So the execution order for me should be task1, task2, task3 and then task4.
Instead the actual execution order is task4, task3, task2, task1. Why!!! bangs own head in frustation!!!!
I also understand that f(g(x)) will execute g(x) first and then f(). But can somebody please explain me why task4 is executed first. I see there is giant gap between my understanding of compose and "how it actually works"
Upvotes: 1
Views: 315
Reputation: 138237
I think the main confusion stems from bad variable names, namely f
andg
, it might get easier to understand if we write:
const compose = (prev, curr) => (...args) => prev(curr(...args));
On every iteration, a function gets created, whereas prev
points to the function created in the previous iteration:
// 1
task1
// 2 (two)
(...args) => task1(task2(...args))
// 3 (three)
(...args) => two(task3(...args))
// 4 (four)
(...args) => three(task4(...args))
// unfolded
(...args) => task1(task2(task3(task4(...args)))
As suggested already there are three possible solutions:
(1) swap curr
and prev
so that curr
gets called first.
(2) Use reduceRight
instead of reduce
(3) Get rid of all the unneccessary closures and do:
const bigTask = (...fns) => arg => fns.reduce((acc, fn) => fn(acc), arg);
Upvotes: 3
Reputation: 418
Call fns.reduce(compose); mean something like this
[task1, task2, task3, task4].reduce(function(accumulator, currentValue, currentIndex, array) {
return accumulator(currentValue())
})
// first step
var s1 = function() {task1(task2())}
// second step
var s2 = function() {s1(task3())}
// third step
var s3 = function() {s2(task4())}
s3()->s2(task4)->s1(task3(task4))->task1(task2(task3(task4())))
Upvotes: 2