Sondear una API inestable hasta el primer éxito

Gana FxDart async

Requisito

El endpoint de estado de un trabajo de exportación es inestable de forma determinista: los cuatro primeros sondeos responden pending y el quinto responde ready. Sondéalo hasta diez veces, guarda un registro de cada sondeo, detente en el primer éxito e informa de qué intento ganó, además de cuántos sondeos se hicieron realmente. Sin aleatoriedad: el número de fallos está fijado en el código de abajo, así que las dos versiones imprimen lo mismo en cada ejecución.

La versión con FxDart escribe el reintento como datos: range(1, 11) es el calendario de sondeos, map es el transporte, peek anota el registro, y dropWhile + head son la política de éxito. Como la cadena es perezosa y se tira de ella valor a valor, head detiene el sondeo: solo llegan a hacerse cinco peticiones.

Salida esperada
polling export-2026-07 (up to 10 attempts):
  poll 1: pending
  poll 2: pending
  poll 3: pending
  poll 4: pending
  poll 5: ready
ready on attempt 5; polls actually made: 5

Lado a lado

Dart nativo

FxDart

Por qué difieren

Con honestidad: el bucle for nativo con un break es corto, y nadie diría que está mal. La diferencia está en dónde vive cada pieza. En el bucle, el presupuesto de intentos, el registro y la prueba de éxito quedan enredados en el flujo de control: cambia uno y tienes que releer el cuerpo entero. En el pipeline, cada preocupación es su propio paso con nombre, así que cambiar la política (primer éxito → tercer éxito, añadir una transformación, ampliar el presupuesto) significa editar una línea. Y la garantía de pereza —ningún sondeo después del ganador— es estructural en FxDart, mientras que en el bucle depende de que el break esté en el sitio correcto.

Benchmark

Apple M1 Max, 32 GB de RAM · Dart 3.12.2 (compilado AOT) · 2026-08-24

Caso async: la escala principal es N = 100,000, no 1,000,000. Cada elemento cuesta una vuelta del event loop en ambos lados, así que un millón de awaits reales mediría el event loop de Dart durante minutos — no el pipeline. Los retardos son de longitud cero y se conserva el límite de concurrencia del ejemplo; lo que comparan las barras es la maquinaria del pipeline.

N = 100

Tiempo Empate

Dart nativo 556 µs
FxDart 645 µs

Memoria pico Empate

Dart nativo 16.4 MB
FxDart 17.1 MB

N = 10,000

Tiempo Gana nativo

Dart nativo 48.2 ms
FxDart 55.5 ms

Memoria pico Gana FxDart

Dart nativo 29.5 MB
FxDart 24.5 MB

N = 100,000

Tiempo Gana nativo

Dart nativo 495.5 ms
FxDart 571.7 ms

Memoria pico Gana FxDart

Dart nativo 56.2 MB
FxDart 50.4 MB

Las barras son medianas de iteraciones cronometradas repetidas en procesos nuevos por lado (los N pequeños se agrupan por resolución del temporizador). Dos lados a menos del 5% entre sí — o a menos de 0.6 ms, una diferencia que nadie puede percibir — cuentan como empate; las carreras relativas ajustadas se vuelven a medir hasta 5 veces. En una app, cualquier cosa por debajo de unos pocos milisegundos es invisible para el usuario, gane la barra que gane. La memoria es el RSS pico del proceso. La VM de Dart y el dataset son idénticos en ambos lados, así que la diferencia entre las dos barras es lo que retiene el pipeline en sí.