What pattern should I use in this example to load and process some data. As value
returns a value, it's not acceptable to have d
as a Future. How can I get the constructor to wait until load
has completed before continuing?
void main() {
var data = new Data(); // load data
print(data.value()); // data.d is still null
}
class Data {
String d;
Data() {
load();
}
Future<void> load() async {
d = await fn(); // some expensive function (e.g. loading a database)
}
String value() {
return d;
}
}
It's possible to call this in the constructor, but you can't await an expression that referenced it.
As per this answer and this article, await is supposed to interrupt code execution and actually wait for the future to complete and then continue executing the rest of the code sequentially. It also suggests that this might block the main thread, which is only logical in that case.
You can only use async/await where you can use promises because they are essentially syntax sugar for promises. You can't use promises in a constructor because a constructor must return the object to be constructed, not a promise.
Dart Future If any code blocks the thread of execution (for example, by waiting for a time-consuming operation or blocking on I/O), the program effectively freezes. Asynchronous operations let your program run without getting blocked. Dart uses Future objects to represent asynchronous operations.
You cannot make a constructor asynchronous.
An asynchronous function needs to return a Future
, and a constructor needs to return an instance of the class itself. Unless the class is a future, the constructor cannot be asynchronous (and even then, it's not really the same thing, and you can't use async
/await
).
So, if your class needs asynchronous set-up, you should provide the user with a static factory method instead of a constructor. I'd usually hide the constructor then.
class Data {
String _d;
Data._();
static Future<Data> create() async {
var data = Data._();
await data._load();
return data;
}
Future<void> _load() async {
_d = await fn();
}
String get value => _d;
}
As an alternative design, I wouldn't even put the load method on the class, just do the operation in the static factory method:
class Data {
String _d;
Data._(this._d);
static Future<Data> create() async => Data._(await fn());
String get value => _d;
}
Obviously other constraints might require that load
has access to the object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With