我正在实现一个返回Stream的函数。我不确定如何实现错误处理,最佳做法是什么?
对于返回Future的函数,最佳做法是never to throw a synchronous error。对于返回Stream的函数也是如此吗?
这是我正在思考的一个例子:
Stream<int> count() {
var controller = new StreamController<int>();
int i = 0;
try {
doSomethingThatMightThrow();
new Timer.repeating(new Duration(seconds: 1), () => controller.add(i++));
} on Exception catch (e) {
controller.addError(e);
controller.close();
}
return controller.stream;
}
答案 0 :(得分:2)
一般来说,Streams也是如此。主要思想是,用户只需要以一种方式处理错误。您的示例将所有错误移至流中。
在某些情况下,即时错误更好(例如,您可能会因为编程错误而导致错误,并且永远不应该处理,或者如果您想保证Stream永远不会产生错误),但是发送错误通过溪流几乎总是一件好事。
小尼特:在某人开始收听之前,流通常(有例外)不会产生任何数据。在你的例子中,你正在启动一个Timer,即使你甚至不知道是否会有一个监听器。我猜这个例子已经减少了,并没有代表你真正的代码,但它是值得注意的。解决方案是使用StreamController的回调进行暂停和订阅更改。
答案 1 :(得分:1)
我已经更新了这个例子,以接受弗洛里安的评论。
在我的实际用例中,我不想缓冲结果,所以如果流暂停,我会抛出UnsupportedError。
我已经把它作为终止流而不是无限流。
如果此函数的用户在几秒钟后异步添加一个侦听器,那么它们将丢失前几个结果。他们不应该这样做。我想这是要清楚记录的东西。虽然也许,如果订阅状态在收到第一个数据后但在收到关闭之前发生变化,我也会抛出错误。
Stream<int> count(int max) {
var controller = new StreamController<int>(
onPauseStateChange: () => throw new UnsupportedError('count() Stream pausing not supported.'));
int i = 0;
try {
doSomethingThatMightThrow();
new Timer.repeating(new Duration(seconds: 1), () {
if (!controller.hasSubscribers)
return;
controller.add(i++);
if (i >= max)
controller.close();
});
} on Exception catch (e) {
controller.addError(e);
controller.close();
}
return controller.stream;
}