Главная » Хабрахабр » [Из песочницы] Ленивые функции в JavaScript

[Из песочницы] Ленивые функции в JavaScript

Привет!

Это будет краткий обзор на то, как создавать функции, как обрабатывать ошибки и чуть-чуть про параллелизм. Подумал я тут рассказать вам о том, как в JavaScript с помощью библиотеки Fluture можно создавать и использовать ленивые функции. Обещаю! Функциональным программированием мозги парить не буду!

Fluture

Future — альтернатива Promise, имеющая куда более мощный API, позволяющий реализовать отмену выполнения (cancellation), безопасную "рекурсию", "безошибочное" выполнение (используя Either) и ещё маленькую тележку крутых возможностей. Fluture — библиотека, разработанная разработчиком Aldwin Vlasblom, реализующая Future.

Думаю, стоит рассказать вам про методы (монады), которые я буду использовать в примерах ниже

  • .of(Any) — создает Future из переданного значения
  • .map(Function) — нет, это не Array.map, это функция трансформации, аналогичная Promise.then
  • .chainRej(Function) — аналогично Promise.catch ловит ошибку
  • .fork(Function, Function) — запускает выполнение Future

Создание ленивой функции

Первый подход заключается в том, что мы создаем функцию, которая принимает исходные данные и возвращает готовую к выполнению Future. Для себя я выделил два основных подхода к созданию ленивых функций в Fluture. Второй подход заключается в том, что мы создаем Future со всеми описанными трансформациями, а затем передаем ей данные.

Давайте на примере! Непонятно? Есть у нас вот такая функция

const multiply10 = x => x * 10;

Теперь сделаем её ленивой, используя первый подход

const multiply10 = x => x * 10; const lazyMultiply10 = (x) => Future .of(x) // Создаем Future из значения .map(multiply10); // Теперь наша функция тут lazyMultiply10(2).fork(console.error, console.log);
// -> 20

Попробуем записать более лаконично, используя второй подход. Слишком громоздко, не правда ли?

const multiply10 = x => x * 10;
const lazyMultiply10 = Future.map(multiply10);
const value = Future.of(2); // Оборачиваем наше значение в Future lazyMultiply10(value).fork(console.error, console.log);
// -> 20

Надо компактнее! Уже лучше, но все еще громоздко.

const lazyMultiply10 = Future.map(x => x * 10); lazyMultiply10(Future.of(2)).fork(console.error, console.log);
// -> 20

На самом деле, эти подходы не являются взаимоисключающими и могут быть использоваться вместе.

const lazyMultiply10 = Future.map(x => x * 10); const someCalculation = a => Future .of(a) .map(v => v + 1) .chain(v => lazyMultiply10(Future.of(v)); someCalculation(10).fork(console.error, console.log);
// -> 110

Обработка ошибок

Давайте вспомним представим функцию, которая делает запрос к стороннему, не очень стабильному, API. Обработка ошибок в Future практически не отличается от обработки ошибов в Promise.

const requestToUnstableAPI = query => request(` }) .then(res => res.data.value) .catch(errorHandler);

Та же функция, но обернутая в Future

const lazyRequestToUnstableAPI = query => Future .tryP(() => request({ method: 'get', uri: `http://unstable-site.com/?${query}` })) .map(v => v.data.value) .chainRej(err => Future.of(errorHandler(err));

Для этого нам понадобится структура Either, а это малость выходит за рамки моего обзора. На самом деле, обработку ошибок можно сделать более гибкой.

Параллелизм

Для работы с параллелизмом в Future реализованы два метода race(Futures[]) (аналогичен Promise.race), parallel(n, Futures[]) и both(Future, Future), но он является частным случаем parallel.

Чтобы сделать поведение parallel таким же как метод Promise.all, нужно количество выполняемых установить как Infinity. Метод parallel принимает два аргумента, количество параллельно выполняемых Future и массив с Future.

Тут тоже без примеров не обойдемся

const requestF = o => Future.tryP(() => request(o));
const parallel1 = Future.parallel(1);
const lazyReqs = parallel1( [ 'http://site.com', 'http://another-site.com', 'http://one-more-site.com', ] .map(requestF)
); lazyReqs.fork(console.error, console.log);
// -> [Result1, Result2, Result3]

Совместимость с Promise

Для этого у Future есть метод .promise(), который, запустит выполнение Future и обернет её в Promise. В JavaScript от Promise никуда не деться, да и вряд ли кто-то будет рад, если ваш метод будет возвращать какую-то непонятную Future.

Future .of(10) .promise();
// -> Promise{value=10}

Ссылки

Если тема интересна, дайте знать, расскажу подробнее про обработку ошибок. Вот, пожалуй, и все, что я вам хотел рассказать. И да, сильно меня не ругайте, это мой первый пост на Хабре.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Из песочницы] Haiku β1 — сделаем /b/ OS великой снова

Совсем недавно (почти 4 месяца назад) вышла новая Haiku (далее — просто BeOS, ибо проект гораздо удачнее ReactOS — настолько, что разница между Haiku и BeOS уже пренебрежимо мала). Да и недавно прочитанный киберпанк-роман Александра Чубарьяна давал понять, что BeOS ...

Минкомсвязи одобрило законопроект об изоляции рунета

Министерство цифрового развития, связи и массовых коммуникаций РФ поддержало законопроект №608767-7 об автономной работе рунета, внесённый в Госдуму 14 декабря 2018 года. Об этом сегодня сообщил замглавы Минкомсвязи Олег Иванов в ходе расширенного заседания комитета Госдумы по информационной политике, информационным технологиям ...