Is it possible to block a function call that returns a future?
I was under the impression calling .then()
does it, but that's not what I'm seeing in my output.
print("1");
HttpRequest.getString(url).then((json) {
print("2");
});
print("3");
What I'm seeing in my output is:
1
3
2
The getString
method doesn't have an async
that would allow me to await
it and then
executes asynchronously in any case.
static Future<String> getString(String url,
{bool withCredentials, void onProgress(ProgressEvent e)}) {
return request(url, withCredentials: withCredentials,
onProgress: onProgress).then((HttpRequest xhr) => xhr.responseText);
}
How do I make it blocking without placing an infinite while loop before step 3 waiting for step 2 to be completed (not that it would work anyways due to the single thread nature of Dart)?
The above HttpRequest loads a config.json
file that determines how everything works in the app, if the request for a field in the config is done before the config.json
file is done loading, it causes errors, so I need to wait until the file is done loading before I allow calling getters on the fields of the class or getters needs to wait for the once-off loading of the config.json
file.
Update, this is what I eventually did to make it work after Günter suggested I use a Completer
:
@Injectable()
class ConfigService {
Completer _api = new Completer();
Completer _version = new Completer();
ConfigService() {
String jsonURI =
"json/config-" + Uri.base.host.replaceAll("\.", "-") + ".json";
HttpRequest.getString(jsonURI).then((json) {
var config = JSON.decode(json);
this._api.complete(config["api"]);
this._version.complete(config["version"]);
});
}
Future<String> get api {
return this._api.future;
}
Future<String> get version {
return this._version.future;
}
}
And where I use the ConfigService
:
@override
ngAfterContentInit() async {
var api = await config.api;
var version = await config.version;
print(api);
print(version);
}
Now I get blocking-like functionality without it actually blocking.
There is no way to block execution until asynchronous code completes. What you can do is to chain successive code so that it is not executed before the async code is completed.
One way to chain is then
print("1");
HttpRequest.getString(url) // async call that returns a `Future`
.then((json) { // uses the `Future` to chain `(json) { print("2"); }`
print("2");
});
print("3"); // not chained and therefore executed before the `Future` of `getString()` completes.
An async call is just scheduling code for later execution. It will be added to the event queue and when the tasks before it are processed it itself will be executed. After an async call is scheduled the sync code `print("3") is continued.
In your case HttpRequest.getString()
schedules a call to your server and registers (json) { print("2")
as callback to be called when the response from the server arrives. Further execution of the application doesn't stall until the response arrives and there is no way to make that happen. What instead happens is that sync code is continued to be executed (print("3")
).
If your currently executed sync code reaches its end, then the next scheduled task is processed the same way.
then()
schedules the code (json) { print("2"); }
to be executed after getString()
completed.
await
async
and await
just make async code look more like sync code but otherwise it is quite the same and will be translated under the hood to xxx.then((y) { ... })
.
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