helmut1978
helmut1978

Reputation: 437

Run async code in synchronous way in Dart

Having the following code:

Future<String> checkPrinter() async {
  await new Future.delayed(const Duration(seconds: 3));
  return Future.value("Ok");
}

String getPrinterStatus() {
  checkPrinter().then((value) {
    return 'The printer answered: $value';
  }).catchError((_) {
    return "Printer does not respond!";
  });
}

void main() {
  print(getPrinterStatus());
}

The output is "null" because the function getPrinterStatus() returns without waiting for checkPrinter to complete (correctly i have a warning telling me that getPrinterStatus does not return a string).

What should i do to make getPrinterStatus to wait for checkPrinter()?

Upvotes: 2

Views: 824

Answers (3)

julemand101
julemand101

Reputation: 31209

There are no such way to make async code to run in a synchronous way in Dart. So you need to make it so async methods returns a Future so it is possible to await the answer.

The problem you have in your code is your are using the then method but does not take into account that this method returns a Future you should return. So e.g.:

String getPrinterStatus() {
  checkPrinter().then((value) {
    return 'The printer answered: $value';
  }).catchError((_){
    return "Printer does not respond!";});
}

The two return statements in this example are used for the method your are giving as argument for then() and are therefore not used to return from getPrinterStatus().

Instead, then() returns a Future<String> which will complete with the value.

So you need to carry the async through your program. Your code could make use of some language features you gets from marking a method async so I have tried to rewrite your code so it works as expected and make use of this features:

Future<String> checkPrinter() async {
  await Future.delayed(const Duration(seconds: 3));
  return "Ok";
}

// Just an example that the method could be written like this.
// Future.delayed takes a computation as argument.
Future<String> checkPrinterShorter() =>
    Future.delayed(const Duration(seconds: 3), () => 'Ok');

Future<String> getPrinterStatus() async {
  try {
    return 'The printer answered: ${await checkPrinter()}';
  } catch (_) {
    return "Printer does not respond!";
  }
}

Future<void> main() async {
  print(await getPrinterStatus());
}

There are some changes I think you should notice:

  • If a method is marked as async the returned value will automatically be packed into a Future<Type> so you don't need to return Future.value("Ok") but can just return Ok.

  • If a method is marked as async you can use await instead of using then(). Also, you can use normal exception handling so I have rewritten getPrinterStatus to do that.

Upvotes: 0

Jitesh Mohite
Jitesh Mohite

Reputation: 34180

 Future<String> getPrinterStatus() async {
    await checkPrinter().then((value) {
      return 'The printer answered: $value';
    }).catchError((_){
      return "Printer does not respond!";});
  }

Upvotes: 1

saturov
saturov

Reputation: 784

Your getPrinterStatus() is not async. main() function will never wait for it's execution.

Make it async. Refactor your main() for something like

void main() {
  getPrinterStatus().then((value) {
    print(value);
  }).catchError((_){
    return "Printer does not respond!";});
}

Upvotes: 0

Related Questions