I build a queue of futures to ensure that those futures get completed in a sequential order, because even if one async function is called before the other this won't ensure that they get executed in this order when pushed on the event loop (my assumption).
In the UI there is a button, every time it gets pressed the async computation is pushed onto this queue. When pressed in a way that the async computation is finished before the next button press there isn't a problem but when pressed fast multiple times the computation won't finish.
In the example below every computation after job 1 won't finish.
int i = 0;
class TouchlessAlarmScheduleQueue {
Future _future = Future(() {});
addJob(String alarmId, Future<void> Function() job) {
print('$i added');
int iCopy = i;
_future = _future.then((_) {
print("$iCopy done");
return job();
});
i++;
}
}
Console Output:
flutter: 0 added
flutter: 0 done
flutter: 1 added
flutter: 2 added
flutter: 1 done
[VERBOSE-2:profiler_metrics_ios.mm(203)] Error retrieving thread information: (os/kern) invalid argument
Not sure if this profiler output is related to the problem.
Worked just fine here:
You should probably only use async/await for clarity. I have done the same thing before. I use an improved version in oun production app: https://twitter.com/gazialankus/status/1364695537585381378
Related
I was going though GSkinner's flutter_vignattes codebase, in one of the functions there was an empty await for a Future
Future<void> _reset() async {
// Wait until next event loop to advance animation and call setState or flutter will yell at you
await Future<void>.value();
_controller.forward(from: 1.0 - _percentage * 0.83);
if (_isLoading) {
setState(() {
_model = BasketballGameModel.randomize();
});
}
_isLoading = false;
}
I understand how promises are sent to micro-task queue in JS (assuming same happens in Dart), but not quite able to understand the reason provided in the comment here i.e.,
// Wait until next event loop to advance animation and call setState or flutter will yell at you
Really appreciate if someone can provide a deeper insight into this. This is the particular line in codebase i am referring to.
https://github.com/gskinnerTeam/flutter_vignettes/blob/0ccc72c5b87b5ab6ba2dee9eff76f48ce2fadec8/vignettes/basketball_ptr/lib/demo.dart#L149
Future<void> function() {}
Defines an asynchronous function that ultimately returns nothing but can notify callers when it eventually completes. Also see: What's the difference between returning void vs returning Future?
Or You can learn from this https://github.com/dart-lang/sdk/issues/33415
I have this specific code:
Stream<MimeMultipart> mm =
MimeMultipartTransformer(boundary).bind(Stream.fromIterable(l));
// Completer. So we can wait for the two response results.
Completer<dynamic> allComplete = Completer<dynamic>();
List<Future> myAsyncs = [];
myAsyncs.add(allComplete.future);
int listenCalledCount = 0;
mm.listen((event) async {
// this listen event executes multiple times...
Completer<dynamic> listenEventCompleted = Completer<dynamic>();
await Future.delayed(const Duration(seconds: 10));
print("Listening!!");
myAsyncs.add(listenEventCompleted.future);
listenCalledCount++; // How many times onData is called..
}, onDone: () => allComplete.complete(true));
await Future.wait(myAsyncs);
// I want all listen function called to be done first before continuing to the code below..
print(listenCalledCount);
print("All Done!");
My expected results are:
flutter: 3
flutter: All Done!
But what currently happening is:
flutter: 0
flutter: All Done!
What it means is, it doesn't wait for the StreamSubscription OnData event functions which is executed more than once to complete. I want all the OnData event functions to complete before proceeding. Is this possible?
I am using Streams in Flutter. The problem is that stream.map() is concurrent which means that it doesn't wait one operation to be performed completely. For example:
_sendClientSubject.stream.map((value) async {
await Future.delayed(const Duration(hours: 1));
// do some operation
}).listen((value) {
// do nothing
});
Here, I want the next stream value to wait until I finish my operation. But the case is, instead of waiting for an hour, map is processing each stream value concurrently.
My question is, how can I perform the operation synchronously in Flutter.
Use asyncMap method from rxdart package.
_sendClientSubject.stream.delay(const Duration(hours: 1)).asyncMap((value) {
// do some operation
}).listen((value) {
// do nothing
});
We know that in Dart everything runs synchronously and according to some definition I found on internet
When you execute something synchronously, you wait for it to finish before moving on to another task. When you execute something asynchronously, you can move on to another task before it finishes.
What I don't understand here is that why b is printed before c I mean if code is running synchronously then it should wait for completion of line 2 to print c and only after printing c
It should print b
Ps- I know I can use async and await keywords to wait for line 2 to complete it's execution. I just want to understand how this synchronous code works.
void main(){
print("a");
Future.delayed(Duration(seconds:
5),(){
print("c");
});
print("b");
}
Output- a
b
c
When you write :
print("a");
Future.delayed(Duration(seconds: 5),(){
print("c");
});
print("b");
You tell the program to print "a", then to launch a Future that will resolve in 5 seconds and print "c", then to print "b"; but you never tell the program to wait for the Future to complete.
Which is synchronous.
And this is why you must use await keyword to make the program wait for the Future completion before moving to next instruction.
No not really. It would only print c before b if you use the await keyword. This keyword tells Dart to wait till this future is complete and then move on to the next task.
For example
void main() async {
print("a");
//await tells dart to wait till this completes. If it's not used before a future, then dart doesn't wait till the future is completed and executes the next tasks/code.
await Future.delayed(Duration(seconds:
5),(){
print("c");
});
print("b");
}
Output
Output- a
c
b
Haven't seen a lot of info about it online...
What are the possible use cases in which I'd want to use, either Future.doWhile, Future.microtask or Future.sync?
Future.sync
A lot of times after a button press for example, I'd want a Future to happen immediately,
but I wouldn't want it to block the UI, is that a good use case for Future.sync or is that better to use Future and let dart handle when thing will get executed?
I'd want a Future to happen immediately...
You can't make Future to happen immediately because it needs some time to be executed. Instead you can block UI thread while future is executing. The pseudo code looks like that:
T runSync<T>(Future<T> future) {
while (future.running) sleep(10);
return future.result;
}
This will block your ui thread. That's why we are using Futures. Futures used for specific tasks that's not resolved immediately (usually I/O tasks, eg: network requests, file read/write) to get notified when future resolves without blocking UI thread.
Here's how I'm handling futures without blocking UI thread:
class MyState extends State<..> {
bool _running = false;
Future<String> doTask() async {
// some long running IO tasks
return 'Hello world';
}
Future handlePress() async {
setState(() { _running = true; });
try {
await doTask();
} finally {
if (mounted) {
setState(() { _running = false; });
}
}
}
Widget build(BuildContext context) {
return FlatButton(
child: Text('Execute'),
// Disable button if task is currently running to block parallel calls (for example sending same http request twice)
onPressed: _running ? null : handlePress,
);
}
}
In this code when user presses FlatButton I'm setting _running to true to disable FlatButton until Future is running.