Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async is snowballing to callers, can't make constructor async

I have a function loadData that loads some text from a file:

Future<String> loadAsset() async {   return await rootBundle.loadString('assets/data/entities.json'); } 

The loadString method is from Flutter SDK, and is asynchronous.

The loadAsset method is then called in another method, that must me marked as async, since loadAsset is async and I need to use await:

Future<List<Entity>> loadEntities() async {   String jsonData = await loadAsset();   return parseData(jsonData); } 

The parseData method is not async, it receives a String, parse it, and return a list of objects:

List<Entity> parseData(String jsonString) {   ... } 

But since loadEntities must be marked with async, this requires that it returns a Future, but in practice, it's not a Future because since I use await, it awaits for the loadAsset method to finish, then call the parseData funcion using the result.

This easily turns into a snowball of async call, because every method that uses loadEntities must be marked as async too.

Also, I can't use loadEntities in a class constructor, because the constructor should be marked as async, which is not allowed in Dart.

Am I using the async/await pattern in Dart wrong? How could I use the loadEntities method in a class constructor?

like image 589
rbasniak Avatar asked Mar 28 '18 15:03

rbasniak


People also ask

Can we make constructor async?

A simple answer for that: No, we can't! Currently, class constructors do not return types, and an asynchronous method should return a Task type.

Can we call async method in constructor?

Just call getWRitings() or whatever async method and don't await it. It won't be done when the constructor ends, but that's ok. Don't use its value there, instead - use its value in another method and call that.

How do you create async constructor?

You can create an async init() {... return this;} method, then instead do new MyClass(). init() whenever you'd normally just say new MyClass() .

What happens when you call async method?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.


2 Answers

No, async is contagious and there is no way to go back from async to sync execution.

async/await is only syntactic sugar for methodThatReturnsFuture().then(...)

Marking a method with async is only to allow you to use await inside its body. Without async you would still need to return a Future for calling code to only execute after the result of loadAsset() becomes available.

like image 130
Günter Zöchbauer Avatar answered Oct 16 '22 18:10

Günter Zöchbauer


You can use the Future returned from the async call directly. This would look something like this:

class HasAsync {   HasAsync() {     asyncFunction().then((val) {       print(val);     });   }    Future<int> asyncFunction() async {      int val = await otherFunction();      return val;   } } 

You just can't use await within the non-async function.

As you've tagged this with 'flutter', I'm going to guess this is within a flutter app. If that's the case look at the docs for FutureBuilder - it might help with what you're trying to do.

like image 25
rmtmckenzie Avatar answered Oct 16 '22 19:10

rmtmckenzie