Esta página ainda não foi traduzida, por isso é exibida em inglês. Ajude a traduzir

Split successes from failures

FxDart wins async

Requirement

Seven orders from the 2026-08 import go through an async validation that throws for two of them (a missing shipping address, an unknown SKU). Keep both outcomes: print an ok: line per valid order, then the failure count. The data is in the code; both versions must print the lines shown under Expected output.

Expected output
ok: order #1001
ok: order #1002
ok: order #1004
ok: order #1005
ok: order #1007
failed: 2

Side by side

RxDart

FxDart

Why they differ

A stream has two channels — data and error — and the error channel has whole-stream semantics: one thrown validation would kill the pipeline with five orders still unprocessed. So the RxDart side cannot simply asyncMap(validate); it wraps each validation in its own inner stream (Rx.fromCallable), catches on that inner error channel with onErrorReturnWith, and re-encodes the failure as a data value before merging back. The recovery works, but it is channel plumbing: the error had to leave the data path just to be escorted back in.

The FxDart side never puts failures on a separate channel. One try/catch inside map turns each outcome into a plain record — (id, error?) — and from there partition is an ordinary predicate split. This is the pull model's general stance on errors: they are values that flow through the same typed pipeline as everything else, so keeping successes and failures together costs nothing. When outcomes are part of the result rather than an interruption, the model without a privileged error channel has less to undo.

Benchmark

Apple M1 Max, 32 GB RAM · Dart 3.12.2 (AOT-compiled) · 2026-08-18

Async case: the headline scale is N = 10,000, not 1,000,000. Every element costs an event-loop turn on both sides, so a million real awaits would measure Dart's event loop for minutes — not the pipeline. Delays are zero-length and the example's concurrency limit is kept; what the bars compare is the pipeline machinery.

N = 100

Time Tie

RxDart 818 µs
FxDart 430 µs

Peak memory Tie

RxDart 17.0 MB
FxDart 16.6 MB

N = 10,000

Time FxDart wins

RxDart 65.2 ms
FxDart 34.8 ms

Peak memory RxDart wins

RxDart 25.2 MB
FxDart 30.6 MB

Bars are medians of repeated timed iterations in fresh processes per side (small N is batched for timer resolution). Sides within 5% of each other — or within 0.6 ms, a difference no person can perceive — count as a tie; close relative races are re-measured up to 5 runs. In an app, anything under a few milliseconds is invisible to the user regardless of which bar is shorter. Memory is peak process RSS. The Dart VM and the dataset are identical on both sides, so the difference between the two bars is what the pipeline itself holds onto.