I'd like to kick off an HttpRequest and then poll for its completion. This feels like a fairly common pattern.
void main() {
_tick(0);
_tickB(0);
build();
print("End of main");
}
void build() {
var path = '../layout.txt';
html.HttpRequest.getString(path).then((String layout) {
print("layout received");
});
}
void _tick(int i) {
print("A $i");
if (i < 10) incr(i).then(_tick);
}
void _tickB(int i) {
print("B $i");
if (i < 10) incr(i).then(_tickB);
}
Future<int> incr(int i) async {
i ;
return i;
}
Output:
A1
B1
End of main
A2
B2
A3
B3
A4
B4
A5
B5
layout received
I would expect to see "layout received" appear interleaved with the other callbacks when the HttpRequest completes but its not. Its always (no matter the value of i
, 5 is just a demo number) at the end of the interleaved callbacks.
Why is this?
How can I schedule the build
callback in such a way that it completes during the other callback chains?
CodePudding user response:
Your incr
function doesn't actually do any asynchronous work. incr
will be executed to completion immediately. Since the returned Future
is already complete, its Future.then
callbacks then will be scheduled in the microtask queue. Only after the microtask queue is empty will the separate event queue be processed. Your _tick
/_tickB
functions therefore create a (temporary) live-lock situation by repeatedly adding events to the microtask queue and preventing your HttpRequest
Future
from completing.
You can get the behavior you expect by making incr
do some asynchronous work:
Future<int> incr(int i) async {
await Future.delayed(Duration.zero);
i ;
return i;
}
and then your output will be:
A 0
B 0
End of main
A 1
B 1
layout received
A 2
B 2
A 3
B 3
...
Further reading: The Event Loop and Dart