share & LiveValue.from

Una ejecución de la cadena, muchos oyentes — y la versión que recuerda su último valor para quien llegue tarde.

FxEvents<T> FxEvents<T>.share({bool reset = true}) // chain (events); resubscribes after last-cancel unless complete LiveValue<T>.from(Stream<T> source) // hot, unseeded LiveValue<T>.seededFrom(T seed, Stream<T> source) // hot, seeded

Lección

Todos los operadores de esta sección construyen su propio StreamController, así que la cadena que devuelven es de suscripción única: escúchala dos veces y el segundo oyente recibe un StateError. Ese comportamiento por defecto es deliberado: mantiene la cadena fría, de modo que nada se ejecuta hasta que alguien la consume, y mantiene honesto el estado por oyente. Pero implica que dos widgets no pueden observar el mismo feed con debounce, throttle y switchMap sin construirlo dos veces.

share() lo arregla. Conecta con el primer oyente y difunde a todos los oyentes a partir de ahí, así que el trabajo aguas arriba ocurre una vez por muchos que estén mirando. Un temporizador de debounce, un socket, un map caro: uno de cada, no uno por suscriptor.

share({reset: true}) — el valor por defecto — ahora coincide con el reset por recuento de Rx. Cuando el último oyente se va antes de que la fuente haya completado, la suscripción de aguas arriba se cancela y el siguiente oyente empieza una suscripción nueva. Después de que la fuente completa, a un oyente tardío se le sigue entregando un stream cerrado. share(reset: false) es el comportamiento de 0.8.7: la última cancelación cierra para siempre. Una resuscripción necesita una fuente que permita un segundo listen — Stream.fromIterable, Stream.multi, FxEvents.defer, un broadcast — un StreamController de suscripción única ya gastado sigue sin poder volver a escucharse. Engancha todos los oyentes antes del primer evento si la fuente es de un solo disparo, o mantén uno vivo.

share() tampoco recuerda: un oyente que llega después de que haya pasado un evento simplemente se lo ha perdido. Para una ventana de historial, shareReplay es la página siguiente. Cuando los rezagados necesitan el estado actual —que es casi toda la UI—, LiveValue es la respuesta, y LiveValue.from(source) / LiveValue.seededFrom(seed, source) construyen uno directamente desde un stream. Esos son calientes: la suscripción se abre de inmediato, así que los valores que llegan antes de que nadie escuche siguen actualizando value, y close() cancela la fuente. Son constructores con nombre en vez de una semilla opcional para que un T nullable pueda sembrarse igualmente con null. Capa de eventos de fxdart, siguiendo a share y shareValue de Rx.

Demo 1 · Por qué un solo oyente es el comportamiento por defecto

Demo 2 · Una ejecución, dos oyentes

Pruébalo tú

Ejercicio: un LiveValue alimentado directamente desde un stream.

Relacionado: shareReplay — multicast que recuerda un búfer de historial · LiveValue — el compartir que recuerda: los suscriptores tardíos reciben primero el valor actual · tee — la respuesta del lado pull a dos lectores sobre una pasada, sin búfer · fork — dos cursores pull independientes sobre una fuente, a costa de un búfer