面向 Dart 的函数式编程,
惰性与并发开箱即用。

FxDart 是 FxTS 的 Dart 移植版本 —— 一个用于在同步与异步数据上组合惰性管道的库, 把六个各耗时 1 秒的串行请求变成 2 秒完成的并发批处理, 只需一次方法调用。

📒 看看实际效果:Daily Ledger —— 用 FxDart 构建的完整应用 →

⚖️ Dart vs FxDart —— 53 个真实任务,并排对比 →

RxDart vs FxDart —— push 对 pull,50 条诚实判定 →

▲ 这是可运行的 —— 修改代码并按下 运行。 它会用真正的 Dart 编译器编译,并在你的浏览器中执行。

FxDart 是什么?

FxDart 把 FxTS 的编程模型带到了 Dart:一套约 120 个小而可组合的函数, 用于变换集合与异步数据。它由三个核心理念定义:

随时间到来的事件,以及作为值的失败,在另外两面上。 选哪一面? 才是 判断;本页仍是介绍页。

为什么需要它?

Dart 已经有 IterableStream。FxDart 的价值, 体现在它们力所不及的地方:

问题原生 DartFxDart
把并发 API 调用限制为 n 个,并保持顺序 手写队列、Completer,以及繁琐的状态管理 .map(fetch).concurrent(3)
异步变换管道 Stream 是基于推送的;把 await、背压和惰性混在一起会变得复杂 基于拉取的链式调用 —— 每个值只在被请求时才计算
数据整理(分组、索引、计数、分区、zip、分块……) 每次都要手写循环 每个概念对应一个经过充分测试的具名函数
可读的多步变换 嵌套调用或中间变量 从左到右的 fx() 链式调用,类型完备

优点 & 缺点

✓ 优点

  • 免费获得惰性 —— 管道会短路;只计算被请求的值。
  • 保序的并发,一个操作符即可实现:concurrent(n) / 按完成顺序输出的 concurrentPool(n)
  • 类型完备的链式调用 —— fx() 让类型推断贯穿始终;同步操作符就是作用于原生 Iterable 的普通函数,因此一切都能与常规 Dart 代码互操作。
  • 小而专注的函数 —— 约 120 个操作符,覆盖变换 / 过滤 / 切片 / 组合 / 聚合 / 对象 / 工具。
  • 久经考验的语义 —— 行为从 FxTS 移植而来,同时带来了它 850+ 个测试。
  • 零依赖 —— 纯 Dart 实现。

✗ 缺点

  • 没有 data-last 柯里化 —— Dart 不支持函数重载,因此 FxTS 柯里化的 pipe 风格在这里变成了链式调用;动态的 pipe() 会丢失静态类型。
  • 多了一层异步抽象 —— FxAsyncIterable 之所以存在,是因为 Stream 无法表达并发的反向通道;桥接很容易,但终究是一个需要额外学习的概念。
  • 学习曲线 —— 用惰性管道思考,与写命令式循环并不相同。
  • 并非总是最快 —— 对于极小的热点循环,手写 for 可能胜过操作符组合;FxDart 的优化目标是清晰度与 I/O 密集型场景。
  • 部分 TS API 无法逐字移植 —— 它们改用了更符合 Dart 习惯的写法:curry 变成了带类型的 .curried 扩展 getter,旧名称则作为已废弃的桩函数保留,便于迁移。

并发初体验

六个各耗时 300 ms 的模拟请求 —— 串行约需 1.8 s,使用 concurrent(3) 约需 0.6 s。试着改改这个数字:

开始学习

FxDart 入门 →

一门循序渐进的课程:讲解、实时演示,以及每个函数配套的 playground。

第一课:map →

从最基础的操作符开始。

安装 →

把 fxdart 加入你的 pubspec,并浏览源码。