2

我正在实现一个返回 Stream 的函数。我不确定如何实现错误处理,最佳实践是什么?

对于返回 Future 的函数,最好不要抛出同步错误。对于返回 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;
}
4

2 回答 2

2

一般来说,Streams 也是如此。主要思想是,用户应该只需要以一种方式处理错误。您的示例将所有错误移动到流中。

在某些情况下,立即错误会更好(例如,您可能会因为编程错误而导致错误并且永远不应该处理,或者如果您想保证 Stream 永远不会产生错误),但是通过流发送错误几乎总是一件好事。

小笨蛋:一个 Stream 通常应该(有例外)在有人开始收听之前不产生任何数据。在您的示例中,您正在启动一个 Timer,即使您甚至不知道是否会有监听器。我猜这个例子是减少的,并不代表你的真实代码,但它是需要注意的。解决方案是使用 StreamController 的回调来进行暂停和订阅更改。

于 2013-03-29T12:51:43.433 回答
1

我已经更新了示例以采纳 Florian 的评论。

在我的实际用例中,我不想缓冲结果,所以如果流暂停,我会抛出 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;
}
于 2013-03-29T21:01:51.637 回答