Reputation: 313
I would like to have an exception thrown inside stream to be caught and handled outside by the caller.
If I try with a standard try-catch block, like below, it does work: I get Uncaught Error: Exception.
By running the snippet code below in DartPad
void main() async {
await for (var i in mainStream()) {
print(i);
}
}
Stream<int> subStreamA() async* {
for (var i in List.generate(10, (i) => i)) {
if (i == 2) {
throw Exception();
}
yield i;
}
}
Stream<int> subStreamB() async* {
for (var i in List.generate(10, (i) => i + 10)) {
yield i;
}
}
Stream<int> mainStream() async* {
try {
yield* subStreamA();
yield* subStreamB();
} catch (e) {
print('CAUGHT! :)');
yield -1;
}
}
The result is:
0
1
Uncaught Error: Exception
I would like the exception to be caught, resulting in:
0
1
CAUGHT! :)
-1
I had some "solution" in mind, but they're kind of horrible :( such as...
Stream<int> mainStream() async* {
try {
Exception? err;
yield* subStreamA().handleError((e) {
err = e;
});
if (err != null) throw err!;
yield* subStreamB().handleError((e) {
err = e;
});
if (err != null) throw err!;
} catch (e) {
print('CAUGHT! :)');
yield -1;
}
}
Is there a clean solution leveraging a normal try-catch without dirty tricks?
Upvotes: 1
Views: 267
Reputation: 31299
The behavior of yield*
for async*
marked method is part of the Dart Language Design which describes this with:
The
o
stream is listened to, creating a subscriptions
, and for each eventx
, or errore
with stack tracet
, ofs
:...
- Otherwise,
x
, ore
witht
, are added to the stream associated withm
in the order they appear ino
.
https://dart.dev/guides/language/specifications/DartLangSpec-v2.10.pdf
So in easier terms, this means when we use yield*
we are forwarding both events and errors (with stacktrace) from the Stream
we are forwarding.
If you want to catch the exceptions, I think the easiest solution is to rewrite the use of yield*
to await for
loops like this:
Stream<int> mainStream() async* {
try {
await for (final event in subStreamA()) {
yield event;
}
await for (final event in subStreamB()) {
yield event;
}
} catch (e) {
print('CAUGHT! :)');
yield -1;
}
}
With this change I get the following output:
0
1
CAUGHT! :)
-1
Upvotes: 3