Dart - 获取流的最后一个或第一个值
Dart - Get the last or the first value of a stream
我有一个流,我需要使用这个流的最后一个值,如果这个流没有发出任何值,我需要等待第一个值。我只想使用一次这个值。正确的做法是什么?
听起来你想要一个流发出的最近事件(这可能是一个广播流,否则在你收听之前没有事件),或者,如果有之前没有活动,您需要 下一个 活动。
对于普通的 Dart Stream
,这是不可能的。它不记得以前的事件。您需要之前收听过该流,以便了解最近的事件是什么(但如果您这样做,它就不一定是广播流)。
您可以相当轻松地构建自己的记忆流包装器(但与异步编程一样,您需要注意竞争条件)
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
import "dart:async";
/// Listens to [source] to returned stream.
///
/// Each listener on the returned stream receives the most recent
/// event sent on [source] followed by all further events of [source]
/// until they stop listening.
/// If there has been no events on [source] yet, only the further events
/// are forwarded.
Stream<T> mostRecentStream<T>(Stream<T> source) {
var isDone = false;
var hasEvent = false;
T? mostRecentEvent;
List<MultiStreamController>? pendingListeners;
var listeners = <MultiStreamController>[];
void forEachListener(void Function(MultiStreamController) action) {
var active = 0;
var originalLength = listeners.length;
for (var i = 0; i < listeners.length; i++) {
var controller = listeners[i];
if (controller.hasListener) {
listeners[active++] = controller;
if (i < originalLength) action(controller);
}
}
listeners.length = active;
}
source.listen((event) {
mostRecentEvent = event;
hasEvent = true;
forEachListener((controller) {
controller.addSync(event);
});
}, onError: (e, s) {
forEachListener((controller) {
controller.addErrorSync(e, s);
});
}, onDone: () {
isDone = true;
for (var controller in listeners) {
controller.close();
}
listeners.clear();
});
return Stream<T>.multi((controller) {
if (hasEvent) controller.add(mostRecentEvent as T);
if (isDone) {
controller.close();
} else {
listeners.add(controller);
}
});
}
有了它,您可以简单地执行 var recentStream = mostRecentStream(yourStream)
,然后再执行 recentStream.first
来获取最近的事件,或者,如果有 none,则下一个事件(如果有是一个,如果流完全为空,则会出现错误。
我有一个流,我需要使用这个流的最后一个值,如果这个流没有发出任何值,我需要等待第一个值。我只想使用一次这个值。正确的做法是什么?
听起来你想要一个流发出的最近事件(这可能是一个广播流,否则在你收听之前没有事件),或者,如果有之前没有活动,您需要 下一个 活动。
对于普通的 Dart Stream
,这是不可能的。它不记得以前的事件。您需要之前收听过该流,以便了解最近的事件是什么(但如果您这样做,它就不一定是广播流)。
您可以相当轻松地构建自己的记忆流包装器(但与异步编程一样,您需要注意竞争条件)
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
import "dart:async";
/// Listens to [source] to returned stream.
///
/// Each listener on the returned stream receives the most recent
/// event sent on [source] followed by all further events of [source]
/// until they stop listening.
/// If there has been no events on [source] yet, only the further events
/// are forwarded.
Stream<T> mostRecentStream<T>(Stream<T> source) {
var isDone = false;
var hasEvent = false;
T? mostRecentEvent;
List<MultiStreamController>? pendingListeners;
var listeners = <MultiStreamController>[];
void forEachListener(void Function(MultiStreamController) action) {
var active = 0;
var originalLength = listeners.length;
for (var i = 0; i < listeners.length; i++) {
var controller = listeners[i];
if (controller.hasListener) {
listeners[active++] = controller;
if (i < originalLength) action(controller);
}
}
listeners.length = active;
}
source.listen((event) {
mostRecentEvent = event;
hasEvent = true;
forEachListener((controller) {
controller.addSync(event);
});
}, onError: (e, s) {
forEachListener((controller) {
controller.addErrorSync(e, s);
});
}, onDone: () {
isDone = true;
for (var controller in listeners) {
controller.close();
}
listeners.clear();
});
return Stream<T>.multi((controller) {
if (hasEvent) controller.add(mostRecentEvent as T);
if (isDone) {
controller.close();
} else {
listeners.add(controller);
}
});
}
有了它,您可以简单地执行 var recentStream = mostRecentStream(yourStream)
,然后再执行 recentStream.first
来获取最近的事件,或者,如果有 none,则下一个事件(如果有是一个,如果流完全为空,则会出现错误。