toAsync
Eleva un Iterable normal —de valores o de Futures— a un FxAsyncIterable, la puerta de entrada al pipeline asíncrono de FxDart.
Lección
Todo pipeline asíncrono de FxDart empieza con toAsync. Toma
un Iterable<FutureOr<T>> normal —una lista de
valores simples, una lista de Futures o una mezcla— y lo envuelve en un
FxAsyncIterable, el tipo que entienden todos los operadores
*Async y la cadena FxAsync. Cada vez que un
elemento resulta ser un Future, se espera automáticamente
conforme se extrae.
FxAsyncIterable está basado en pull: nada se
ejecuta hasta que un terminal (toListAsync,
eachAsync, el .toList() de la cadena
FxAsync, …) llama a next() sobre él, un paso
cada vez — exactamente igual que un Iterable normal, solo que
asíncrono. Es un alejamiento deliberado del Stream de
Dart, que está basado en push: en cuanto un stream empieza a
emitir, es él quien decide el ritmo, y un consumidor aguas abajo no tiene
forma de decirle «evalúa 3 de estos a la vez». El protocolo
next([Concurrent? concurrent]) de FxDart añade justo ese
canal de retorno: un operador aguas abajo como concurrent(n)
puede pasar un marcador aguas arriba con cada pull, pidiéndole a
la fuente que ejecute n elementos en paralelo. Los Streams no
ofrecen ningún punto de enganche equivalente, y esa es justo la razón por
la que FxDart define su propio iterable asíncrono en vez de construir sobre
Stream.
Usa el toAsync(iterable) de nivel superior para un
Iterable<FutureOr<T>> en crudo, o el método de
cadena fx(iterable).toAsync() para pasar una cadena
Fx existente a su equivalente FxAsync. Ambos son
perezosos: construir el pipeline no hace nada hasta que algo tira de él.
Demo 1 · Valores, Futures y la forma encadenada
toAsync acepta valores simples, Futures o una mezcla de
ambos — y la forma encadenada hace lo mismo a partir de un Fx
existente:
Demo 2 · Por qué importa el modelo basado en pull
En Dart, un Future empieza a ejecutarse en el instante en que
se crea, no cuando se espera. Así que tres Futures construidos de forma
ansiosa en un literal de lista ya se están ejecutando en paralelo antes de que
toAsync los toque siquiera. Compáralo con
mapAsync (o el .map de la cadena), que crea un
Future nuevo por elemento solo cuando se tira de él — de forma
perezosa, uno a uno, salvo que añadas concurrent(n):
La forma con método
xs.fxAsync es esta función como getter. Devuelve un
FxAsync y no un FxAsyncIterable pelado, así que
la cadena puede continuar — y resuelve los futuros, cosa que
xs.fx no hace.
await responses.fxAsync.map(parse).concurrent(4).toList();
// responses.fx would be an Fx<Future<T>> — a chain over the
// futures rather than their values.
El nombre lleva fx a propósito: toAsync es una
expresión lo bastante general como para no decir, sobre un
Iterable pelado, en qué librería se entra. Las formas con
getter están recogidas en fx.
Pruébalo tú
Ejercicio: filtra la lista de abajo para que solo las notas aprobadas (>= 60) lleguen al resultado.
*Async — mapAsync, filterAsync, … ·
puentes con Stream — fromStream, fxStream, toStream ·
concurrent — el canal de retorno en acción ·
delay & sleep — para construir demos asíncronas