1

I am using flutter_bloc library.

In the bloc, the mapEventToState method is an async* function which returns Stream<BlocState>. From this function I am calling other async* functions like this yield* _handleEvent(event)

In such method, I am calling some Future returns functions but in the Future then() function it wont let me call other yield* functions.

Here is an example:

Stream<BlocState> mapEventToState(BlocEvent event) async*{
     yield* _handlesEvent(event); //This calls to worker method 
}

Stream<BlocState> _handleEvent(BlocEvent event) async* {
   _repository.getData(event.id).then((response) async* { //Calling Future returned function
         yield* _processResult(response); //This won't work
     }).catchError((e)  async* {
         yield* _handleError(e);  //This won't work either
     });

   Response response = await _repository.getData(event.id); //This do works but I want to use it like above, is it possible?
   yield* _processResult(response); //This do works
}

The question is however, how to combine between Future and Stream in dart. I could use await _repository.getData which works. but then I won't catch the error.

4
  • use simple await instead of then: var response = await _repository.getData(event.id); yield* _processResult(response); Commented Jun 4, 2020 at 15:46
  • Thanks, I've mentioned this in my question, how do I catch the error like this? I wanted to use the built in catch error of the Future api. Commented Jun 4, 2020 at 17:47
  • use normal try-catch - what does not work that way? Commented Jun 4, 2020 at 17:49
  • Thanks, please refer my reply to @Candace below Commented Jun 4, 2020 at 18:06

3 Answers 3

1
  1. await is just syntactic sugar for .then(), and putting await in a try-catch block is syntactic sugar for using .catchError. Things that you can do one way can be done with the other.

  2. In your first version that uses .then()/.catchError(), your function doesn't return anything.

  3. Your callbacks won't work because you're using yield* in them, but you haven't specified the callbacks with sync* or async*. To avoid name collisions, the yield keyword requires them (in the same way that await requires a function use async or async*).

Here's a version that should work with .then() and .catchError():

Stream<BlocState> _handleEvent(BlocEvent event) async* {
  yield* await _repository.getData(event.id).then((response) async* {
    yield* _processResult(response);
  }).catchError((e) async* {
    yield* _handleError(e);
  });
}

Note that the callbacks don't need to use yield*; they could just return their Streams directly:

Stream<BlocState> _handleEvent(BlocEvent event) async* {
  yield* await _repository.getData(event.id).then((response) {
    return _processResult(response);
  }).catchError((e) {
    return _handleError(e);
  });
}

But (as everyone else has noted) using await instead of the Future API simplifies the whole thing (especially since we're already using await anyway):

Stream<BlocState> _handleEvent(BlocEvent event) async* {
  try 
    response = await _repository.getData(event.id);
    yield* _processResult(response);
  } catch (e) {
    yield* _handleError(e);
  }
}

See https://dartpad.dartlang.org/fc1ff92e461754bdb35b998e7fbb3406 for a runnable example.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, of course, the _processResult and _handleError are generators which eventually yields the final State to the steam. yield won't work in the callbacks either as they are closures.
@MotiBartov I don't understand what you mean by "yield won't work in the callbacks either as they are closures". I'm saying you need to change (response) { yield* ... } to (response) async* { yield* ... }.
I've tried this, it won't work. The (respose){} is actually an internal object no? The scope of it doesn't allow to yield* or yield to the stream of the outer class function
(response) { ... } constructs an anonymous function. You absolutely can add async, async*, sync* to anonymous functions.
Generally you're correct, but remember that these outer function returns Stream<BlocState>, the anonymous function return type not defined so even I'd I set it async* its not the same stream. When I tried this it didn't worked.
1

Try using a try-catch block instead. It works for me with await operations.

2 Comments

Thanks, I thought about this but the Future api already has catch error api, I just wondered if I can use it. It's like wrapping try-catch with another try-catch
@MotiBartov It's not wrapping anything. The Dart compiler will automatically convert try { await future; } catch { ... } to an appropriate future.then().catchError() construct. It's syntactic sugar.
0

To handle errors in an async function, use try-catch:

try {
  Response response = await _repository.getData(event.id)
} catch (err) {
  print('Caught error: $err');
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.