Трансдьюсеры в Javascript

Ruslan Rashidov
4 min readNov 1, 2020

--

Photo by Ivan Torres on Unsplash

Трансдьюсеры — это функции которые на вход получают редьюсер и возвращают так же редьюсер. Чтобы понять для чего они нужны и как их применять, давайте рассмотрим пример.

Допустим у нас есть массив. Значениями массива будут объекты описывающие пиццу🍕🍕🍕:

Добавим грибов, отфильтруем пиццы маленького размера и добавим помидоры:

Основная проблема в данном случае — это промежуточные массивы. Между вызовом каждой из функций map, filter, map создается промежуточный массив.

Это не так страшно, если в массиве мало элементов, но, что если массив содержит 100000 элементов или больше. Мы создаем 2 промежуточных массива по 100000 элементов, что отрицательно сказывается на производительности и потребляемой памяти.

Здесь то на помощь к нам и приходят трансдьюсеры. Они позволяют производить выше описанные трансформации над массивом без создания дополнительных промежуточных массивов.

Итак, как все это работает?

Для начала надо ознакомится с такой функцией как compose. Она необходима для создания композиции функций. Что такое композиция функций? foo(bar(baz(value))) вот композиция функций. С помощью compose это будет выглядеть вот так:

Ниже показан один из вариантов реализации функции compose:

Как мы знаем, любую функцию map или filter можно заменить функцией reduce. Reduce — это функция, которая первым аргументом принимает функцию редьюсер, а вторым аргументом объект, используемый в качестве первого аргумента редьюсера. Перепишем наш код с использованием функции reduce. Для удобства не будем подключать второй map с помидорами:

Для наглядности вынесем редьюсеры в отдельные функции:

К сожалению, мы не можем использовать композицию функций с редьюсерами, т.к. редьюсер принимает два параметра, а возвращает один, т.е. следующий код не будет работать:

Будем исправлять эту ситуацию. Для этого вынесем общую часть наших редьюсеров в отдельную функцию, которая также является редьюсером:

А наши редьюсеры перепишем в более универсальные функции:

Теперь с помощью этих функций мы можем получить наши первоначальные редьюсеры:

Готово, мы написали наши первые трансдьюсеры getMushroomsReducer, getSizeReducer.

Вспомним, трансдьюсер — это функция которая на вход получают редьюсер и возвращают так же редьюсер. Наши функции getMushroomsReducer, getSizeReducer получают на вход редьюсеры и возвращают так же редьюсеры. А это значит, что теперь мы можем использовать композицию с нашими трансдьюсерами. То есть, мы можем переписать вышестоящий код следующим образом:

Или с использованием нашей функции compose:

Рассмотрим как это работает подробнее:

Теперь, когда мы разобрались почему композиция работает, преобразуем наши трансдьюсеры, в более универсальные функции. Для этого вынесем для map трансдьюсера ту часть, которая отвечает за трансформацию значения, а в filter трансдьюсере ту часть, которая отвечает за условный выбор:

addMushrooms и filterSmallPizza — это те функции которые мы передавали в качестве первого аргумента для map и filter в начале статьи, т.е.

Теперь мы можем заменить этот код трансдьюсерами, который будет делать все тоже самое, но без промежуточных массивов:

Рассмотрим подробнее как это работает на диаграмме:

Функция compose вызывает функции справа на лево, таким образом последней вызывается sizeTransducer, которая возвращает редьюсер, который мы передаем в функцию reduce. Затем, будет вызван редьюсер возвращаемый функцией mushroomsTransducer и последней вызывается функция arrReducer, которая и производит изменения над вторым параметром функции reduce, в данном случае это пустой массив []. Таким образом, значения массива pizzas проходят преобразования, не создавая при этом промежуточные массивы.

В данной статье я попытался объяснить, что такое трансдьюсеры и как они работают. Для того чтобы использовать трансдьюсеры, в вашем проекте, вам не обязательно их реализовывать самому, трансдьюсеры и многие другие полезные функции реализованы в библиотеке для функционального программирования Ramda.

Весь код который использовался в данной статье, вы можете скачать в репозитории https://github.com/tessierashpool/transducers-article. Для удобства каждая ветка репозитория представляет собой шаг описываемый в статье. Ветка final содержит код для замера производительности кода, надписанного обычным способом и с помощью трансдьюсеров.

Трансдьюсеры — это только часть инструментов, которое предоставляет функциональное программирование. Если вас заинтересовало функциональное программирование, рекомендую вам прочитать книгу Composing Software by Eric Elliott.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Responses (1)

Write a response