← Back

Problems and reducers

We want to display a video in a web application. We have the video in different formats and resolutions. The place to put the video in changes size depending on the device and orientation.

We want to use the only mp4 format and download the video with bigger than the space of but not more. In other words: we want to optimize the downloading.

Question: how to find the correct video from the list using a reducer?

Working with arrays in JS #

Compared to other languages (Ruby, I'm looking at you) JS have only a few methods to manipulate arrays. The basics are:

But I'd say that most of the time, using filter, find and sort is enough.

Solve the problem, the easy way #

In our case, what we want:

In plain JS:

const source = sources
.filter(x => x.format === 'mp4')
.filter(x => x.width > elementWidth)
.sort((a, b) => a.width - b.width)
[0];

How to use a reducer #

Ok. As I written before, reducer is the "mother" of all functions, because every other can be implemented with reducer.

The reducer function receives two parameters. First is expected output (normally called "accumulator") and second is the current item of the array.

The return value from the reducer in one iteration, will become the accumulator parameter in the next iteration.

The "hello world" of the reducers is "sum":

const sum = [1, 2, 3, 4].reduce(
(acc, num) => acc + num), // <= the reducer
0 // <= the initial value of the accumulator
)

sum // => 10

Another canonical example is to convert an array into an object. In this case, we are returning the same result on every iteration, so the accumulator will be always the same:

const array = ['a', 'b', 'c']

const object = array.reduce((acc, item) => {
acc[item] = true;
return acc;
}, {}) // <= this second parameter {} is the accumulator

object // => { a: true, b: true, c: true }

Last but not least, in Javascript, if we don't specify an initial value of the accumulator, first first iteration of the reductor will contain the first and second element of the array.

For example, the following code:

const array = [1, 2, 3, 4]

const result = array.reduce((acc, item) => {
console.log({ acc, item });
return item;
})

will output:

{ acc: 1, item: 2 } // <= first two items of the array
{ acc: 2, item: 3 } // <= we returned the item from last iteration
{ acc: 3, item: 4 } // <= same

and the result will be 4.

The good thing of a reducer is that it can combine all other operations into one, as we will see in our example.

The solution #

Ok, maybe it was a too long introduction to reducers. Here's the solution:

sources.reduce((selected, item) => {
return (item.format === 'mp4' &&
item.width > elementWidth &&
item.width < selected.width) ? item : selected;
})

What do you prefer? The "easy" or the "reducer" solution?

The real solution #

Spoiler: don't solve the problem, destroy it.

I really think we, as application developers, shouldn't do this kind of optimizations. This is something the browser should do it by default (the same way it does for images, for example).

In fact, I think this kind of optimization could bring more problems than solutions. For example, what happens if the device size changes? Or if some one video is already downloaded (and cached) and we force to download another (even if it's smaller)?

I mean: only browser vendor are able to solve this kind of problems because they have all the information required to solve it (like cache and network status, device capabilities, common usage patterns, etc).

We should focus on solve our own (application domain) problems.

In this specific example, I don't think the optimization is relevant because, for most of our users, the mobile network nowadays works as well (if not better) than the wired network. And there are lot of issues to solve in order to optimize correctly.

My preference #

If you are wonder, I prefer the easy way to solve the problem (using filter, find and sort) than the reducer version. Basically two reasons:

Conclusion #

As a conclusion (what we all already know in theory, but which is much more difficult to apply in practice):