Функциональное программирование для Dart,
с ленивостью и конкурентностью из коробки.

FxDart — это порт FxTS на Dart: библиотека для композиции ленивых конвейеров над синхронными и асинхронными данными, где превращение шести последовательных запросов по секунде в конкурентную пачку за две секунды — это один вызов метода.

📒 Посмотрите в деле: Daily Ledger — полноценное приложение на FxDart →

⚖️ Dart vs FxDart — 53 реальные задачи, бок о бок →

RxDart vs FxDart — push vs pull, 50 честных вердиктов →

▲ Это живой пример — измените код и нажмите Запустить. Он компилируется настоящим компилятором Dart и выполняется в вашем браузере.

Что такое FxDart?

FxDart переносит модель программирования FxTS в Dart: набор из ~120 небольших композируемых функций для работы с коллекциями и асинхронными данными. В его основе три идеи:

События во времени и отказы как значения живут на двух других слоях. Какой слой? — это решение; эта страница остаётся маркетинговой.

Зачем это нужно?

В Dart уже есть Iterable и Stream. FxDart оправдывает себя там, где их возможностей не хватает:

ЗадачаЧистый DartFxDart
Ограничить число одновременных вызовов API до n, сохранив порядок Ручные очереди, Completer, кропотливый учёт .map(fetch).concurrent(3)
Асинхронные конвейеры преобразований Stream работает по push-модели; смешивать await, backpressure и ленивость становится непросто Pull-цепочка — каждое значение вычисляется только по запросу
Обработка данных (группировка, индексация, подсчёт, разбиение, zip, chunk…) Каждый раз самописные циклы По одной проверенной именованной функции на каждое понятие
Читаемые многошаговые преобразования Вложенные вызовы или промежуточные переменные Цепочки fx() слева направо, полностью типизированные

Плюсы & минусы

✓ Плюсы

  • Ленивость бесплатно — конвейеры прерываются досрочно; вычисляются только запрошенные значения.
  • Конкурентность с сохранением порядка одним оператором: concurrent(n) / concurrentPool(n) в порядке завершения.
  • Полностью типизированные цепочкиfx() сохраняет вывод типов от начала до конца; синхронные операторы — обычные функции над нативными Iterable, поэтому всё совместимо с обычным Dart.
  • Небольшие узкоспециализированные функции — ~120 операторов: transform / filter / slice / combine / aggregate / object / util.
  • Проверенная в бою семантика — поведение перенесено из FxTS вместе с 850+ его тестов.
  • Ноль зависимостей — чистый Dart.

✗ Минусы

  • Нет каррирования с данными в конце — в Dart нет перегрузки функций, поэтому каррированный стиль pipe из FxTS превращается в цепочки; динамический pipe() теряет статические типы.
  • Вторая асинхронная абстракцияFxAsyncIterable существует потому, что Stream не умеет выражать обратный канал для конкурентности; мосты просты, но это ещё одно понятие для изучения.
  • Порог входа — мышление ленивыми конвейерами отличается от императивных циклов.
  • Не всегда самый быстрый вариант — на маленьких горячих циклах написанный вручную for может обогнать композицию операторов; FxDart оптимизирован под ясность и работу с I/O.
  • Некоторые API из TS не переносятся буквально — вместо этого они получают нативные для Dart формы: curry стал типизированным геттером-расширением .curried, а старые имена оставлены как deprecated-заглушки для миграции.

Конкурентность на вкус

Шесть фиктивных запросов по 300 мс — последовательно ~1,8 с, с concurrent(3) около 0,6 с. Попробуйте изменить число:

Начать обучение

FxDart 101 →

Пошаговый курс: лекции, живые демо и playground для каждой функции.

Первый урок: map →

Начните с самого базового оператора.

Установка →

Добавьте fxdart в свой pubspec и посмотрите исходный код.