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?
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
Related
the official Bloc documentation gives this code snippet:
Stream<int> countStream(int max) async* {
for (int i = 0; i < max; i++) {
yield i;
}
}
This looks very simple to me, until I realize that the function does not return anything (no returnstatement), but yields all the time (which is to me - coming from python - not the same as a return statement).
There's also this example, which is even more clear:
Future<int> sumStream(Stream<int> stream) async {
int sum = 0;
await for (int value in stream) {
sum += value;
}
return sum;
}
Here there's an int returned explicitly, but if I read this correctly the function definition should return a Future<int>type:
Future<int> sumStream(Stream<int> stream) async { //...
Now, how does this work? I'm a bit confused here.
Thanks in advance!
Axel.
For your first example, countStream is a Stream of integer designed with an async*. (take care of the star)
In this stream definition, Yield emit a new integer on the stream flow (of integer as said by stream < int > .
If you consume the stream, you will get 0,1,2,3,4,...,max-1
In the second snippet, read it as : sumStream is a Future that must return an int.
More generally, A Future < T > instance produces a value of type T.
sumStream will consume a stream (given in parameter) and as long as this stream has values, sum them and return the last sum when finished. Sum is an integer : it's ok with Future definition.
Using both, you can have :
> void main() async {
print(await sumStream(countStream(5)));
}
result : 10 (0+1+2+3+4)
As sumStream is a Future, main can wait for asynchronous execution: it declares its intention to use async function (async declaration), then it can use await to stop its own execution until sumStream returns.
Another way if you leave main without async is to add a .then clause to the Future:
void main() {
sumStream(countStream(5)).then((x)=>print(x));
print("after sumStream");
}
Result :
after sumStream
10
As you can see main pass over sumStream it has started but which is not finished and print("after sumStream") first.
Then the main finished, but Dart knows there is still async job running and it will wait until all is done, so we can see the result, but once Future sumStream is finished.
HTH
This looks very simple to me, until I realize that the function does not return anything (no return statement)
First of all, this function returns Stream<int> result value as specified in function declartion. This function often called as the generator function.
Stream<int> countStream(int max) async*
The function body code (generator) will generate the int values and yield these generated values to the initially returned Stream<int> stream.
The statement yield means in this case the following logic of work:
Add a value to Stream<int> controller and return to the next statement in the body of the function that follows that statement yield.
Something like this:
import 'dart:async';
Future<void> main() async {
await for (final i in countStream(5)) {
print(i);
}
}
Stream<int> countStream(int max) {
int i;
final _ctl$ = StreamController<int>();
void Function(int) _switchState$;
_switchState$ = (int _state$) {
while (true) {
switch (_state$) {
case 0:
// for (int i = 0;
i = 0;
_state$ = 1;
break;
case 1:
// i < max;
if (i < max) {
_state$ = 2;
} else {
return;
}
break;
case 2:
// yield i;
_ctl$.add(i);
Timer.run(() => _switchState$(3));
return;
case 3:
// i++
i++;
_state$ = 1;
break;
}
}
};
Timer.run(() => _switchState$(0));
return _ctl$.stream;
}
Result:
0
1
2
3
4
I'm making a Flutter app that using asynchronous a lot but it not working like how I understand about it. So I have some question about async and await in dart. Here is an example:
Future<int> someFunction() async {
int count = 0;
for (int i=0; i< 1000000000;i ++) {
count+= i;
}
print("done");
return count;
}
Future<void> test2() async {
print("begin");
var a = await someFunction();
print('end');
}
void _incrementCounter() {
print("above");
test2();
print("below");
}
test2() function will take a lot of time to done. right? So what i want is when test2 keep his work running until done, everything will keep running and not wait for test2().
When i run the function _incrementCounter(), it show the result:
above begin done below end
The problem is it didn't show "below" right away but it wait until someFunction() done.
This is result i want:
above begin below done end
This is the expected behavior since this change in Dart 2.0 which can be found in the changelog:
(Breaking) Functions marked async now run synchronously until the first await statement. Previously, they would return to the event loop once at the top of the function body before any code runs (issue 30345).
Before I give the solution I want to note you that async code are not running in another thread so the concept of:
keep his work running until done, everything will keep running and not
wait for test2()
Is fine but at some point your application are going to wait for test2() to finish since it is spawned as a task on the job queue where it will not leave other jobs to run before it is done. If you want the experience of no slowdown you want to either split the job into multiple smaller jobs or spawn an isolate (which are running in another thread) to run the calculation and later return the result.
Here is the solution go get your example to work:
Future<int> someFunction() async {
int count = 0;
for (int i=0; i< 1000000000;i ++) {
count+= i;
}
print("done");
return count;
}
Future<void> test2() async {
print("begin");
var a = await Future.microtask(someFunction);
print('end');
}
void _incrementCounter() {
print("above");
test2();
print("below");
}
main() {
_incrementCounter();
}
By using the Future.microtask constructor we are scheduling the someFunction() to be running as another task. This makes it so the "await" are going to wait since it will be the first true instance of an async call.
I've spent many hours looking for the solution, but since I am Dart begginer, I couldn't find it out by myself.
What I want to achieve is to create something like queue for some of the async functions that are called randomly (let's say, when user is tapping a button in my app) from different points in code while the app is running. I want them to be executed in the order they were called, so basically I have async methods such as updateDate() and updatePoints() and when the user is tapping button X the updateDate() is going to be called (added to queue), and similar with Y and updatePoints(). When the user taps i. e. X, X, Y I want to run updateDate(), updateDate(), updatePoints() in this exact order. When one task is complete, another one is starting. I guess I can't use await to achieve that. Any hints would be appreciated!
import 'dart:async';
import 'dart:collection';
import 'dart:math';
Future<void> main() async {
_simulateRealWork();
}
Scheduler _scheduler = Scheduler();
class Scheduler {
bool _scheduled = false;
Queue<Future Function()> _queue = Queue<Future Function()>();
void schedule(Future Function() task) {
_queue.add(task);
if (!_scheduled) {
_scheduled = true;
Timer(Duration(seconds: 0), _execute);
}
}
Future _execute() async {
while (true) {
if (_queue.isEmpty) {
_scheduled = false;
return;
}
var first = _queue.removeFirst();
await first();
}
}
}
void _simulateRealWork() {
var maxPeriod = 5;
var count = 5;
for (var i = 0; i < count; i++) {
print('Timer $i');
var random = Random();
Timer(Duration(seconds: random.nextInt(maxPeriod)), () {
print('Scheduled work $i');
Future work() async {
print('Started work $i');
await Future.delayed(Duration(seconds: random.nextInt(maxPeriod)));
print('Ended work $i');
}
_scheduler.schedule(work);
});
}
}
Result:
Timer 0
Timer 1
Timer 2
Timer 3
Timer 4
Scheduled work 2
Started work 2
Scheduled work 0
Scheduled work 3
Ended work 2
Started work 0
Scheduled work 1
Scheduled work 4
Ended work 0
Started work 3
Ended work 3
Started work 1
Ended work 1
Started work 4
Ended work 4
The following code might be a bad practice when used in large queue of tasks, but if you are sure that the array of tasks won't exceed an adequate size - this might work just fine:
Future<List<T>> runOneByOne<T>(List<T Function()> list) {
if (list.isEmpty) {
return Future.value(null);
}
Future task = Future<T>.microtask(list.first);
final List<T> results = [];
for (var i = 1; i < list.length; i++) {
final func = list[i];
task = task.then((res) { results.add(res); return Future<T>.microtask(func); });
}
return task.then((res) { results.add(res); return results; });
}
It executes functions one-by-one in the original order by wrapping one Future into another. results array is used to store returned values, returning all of the values in the end.
Execution stops and throws if stumbled upon an error. Results array is lost in that case. You can add try {...} closure to every microtask wrapper to ignore errors and return null in that one particular task, preserving other values in results array.
Usage example:
runOneByOne<int>([
() { print("First"); return 1; },
() { print("Second"); return 2; },
() { print("Third"); return 3; },
]).then((results) {
print(results); // List<int> [ 1, 2, 3 ]
});
I am making an application using flutter framework .
During this I came across with the keywords in Dart async and async*.
Can anybody tell me what's the difference between them?
Short answer
async gives you a Future
async* gives you a Stream.
async
You add the async keyword to a function that does some work that might take a long time. It returns the result wrapped in a Future.
Future<int> doSomeLongTask() async {
await Future.delayed(const Duration(seconds: 1));
return 42;
}
You can get that result by awaiting the Future:
main() async {
int result = await doSomeLongTask();
print(result); // prints '42' after waiting 1 second
}
async*
You add the async* keyword to make a function that returns a bunch of future values one at a time. The results are wrapped in a Stream.
Stream<int> countForOneMinute() async* {
for (int i = 1; i <= 60; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
The technical term for this is asynchronous generator function. You use yield to return a value instead of return because you aren't leaving the function.
You can use await for to wait for each value emitted by the Stream.
main() async {
await for (int i in countForOneMinute()) {
print(i); // prints 1 to 60, one integer per second
}
}
Going on
Watch these videos to learn more, especially the one on Generators:
Isolates and Event Loops
Futures
Streams
async / await
Generators
Marking a function as async or async* allows it to use the async/await for a Future.
The difference between both is that async* will always return a Stream and offer some syntactical sugar to emit a value through the yield keyword.
We can therefore do the following:
Stream<int> foo() async* {
for (int i = 0; i < 42; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
This function emits a value every second, which increments every time.
Solution, Origins and Insights
This answer includes simplified and easy to understand examples
async
The async computation cannot provide a result immediately when it is started because the program may need to wait for an external response like:
Reading a file
Querying a database
Fetching data from an API
Instead of blocking all computation until the result is available, the asynchronous computation immediately returns a Future object which will eventually "complete" with the result.
Example (This type of async call can be used only without returning a response):
void main() async {
// The next line awaits 5 seconds
await Future.delayed(Duration(seconds: 5));
// Pseudo API call that takes some time
await fetchStocks();
}
Future
A Future represents a computation that doesn’t complete immediately. Whereas a normal function returns the result, an asynchronous function returns a Future, which will
eventually contain the result. The Future will tell you when the result is ready.
Future is appended when the async function returns a value
Represents the result of a single computation (in contrast to a Stream)
Example:
Future<String> fetchUserOrder() =>
// Imagine that this function is more complex and slow.
Future.delayed(
const Duration(seconds: 2),
() => 'Large Latte',
);
void main(List<String> arguments) async {
var order = await fetchUserOrder();
// App awaits 2 seconds
print('Your $order is ready');
}
Stream
A source of asynchronous data events.
A Stream provides a way to receive a sequence of events. Each event is either a data event, also called an element of the stream.
Stream is a sequence of results
From stream you get notified for results (stream elements)
async* (streams)
async* is an asynchronous generator that returns a Stream object. Made to create streams.
An example of using a stream and async*:
// Creating a new stream with async*
// Each iteration, this stream yields a number
Stream<int> createNumberStream(int number) async* {
for (int i = 1; i <= number; i++) {
yield i;
}
}
void main(List<String> arguments) {
// Calling the stream generation
var stream = createNumberStream(5);
// Listening to Stream yielding each number
stream.listen((s) => print(s));
}
Result:
1
2
3
4
5
Bonus: Transforming an Existing Stream
If you already have a stream, you can transform it to a new stream based on the original stream’s events.
Example (same code as before but with a twist):
Stream<int> createNumberStream(int number) async* {
for (int i = 1; i <= number; i++) {
yield i;
}
}
// This part is taking a previous stream through itself and outputs updated values
// This code multiplies each number from the stream
Stream<int> createNumberDoubling(Stream<int> chunk) async* {
await for (final number in chunk) {
yield number*2;
}
}
void main(List<String> arguments) {
// Here we are Transforming the first stream through createNumberDoubling stream generator
var stream = createNumberDoubling(createNumberStream(5));
stream.listen((s) => print(s));
}
Result:
2
4
6
8
10
Solution
The async and async* are close relatives, they are even from the same library dart:async
The async represent a Future and a one-time exchange while the async* represents a Stream, a stream of multiple events
Async functions execute synchronously until they reach the await keyword. Therefore, all synchronous code within an async function body executes immediately.
Future<int> foo() async {
await Future.delayed(Duration(seconds: 1));
return 0;
}
Async* is used to create a function that returns a bunch of future values one at a time. Each result is wrapped in a Stream.
Stream<int> foo() async* {
for (var i = 0; i < 10; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
async* will always return a Stream
Stream<int> mainStream(int value) async* {
for (int i = 1; i <= value; i++) {
yield i;
}
}
async returns the result wrapped in the Future. So it might take longer time. See the below example:
void main() async {
// The next line awaits 10 seconds
await Future.delayed(Duration(seconds: 10));
}
inside my flutter app I want to check my api every 10 seconds. I found this post to run a function every x amount of time and did the following:
class _MainPage extends State<MainPage> {
int starter = 0;
void checkForNewSharedLists(){
// do request here
setState((){
// change state according to result of request
});
}
Widget build(BuildContext context) {
Timer.periodic(Duration(seconds: 15), (Timer t) => checkForNewSharedLists());
}
}
Unfortunately the requests pile up: after restarting the app on the first "round" there are two request to the api, the second round it's four requests, the third it's eight and so on...
Does anybody know how to fix this?
build() can and usually will be called more than once and every time a new Timer.periodic is created.
You need to move that code out of build() like
Timer? timer;
#override
void initState() {
super.initState();
timer = Timer.periodic(Duration(seconds: 15), (Timer t) => checkForNewSharedLists());
}
#override
void dispose() {
timer?.cancel();
super.dispose();
}
Even better would be to move out such code from widgets entirely in an API layer or similar and use a StreamBuilder to have the view updated in case of updated data.
Use Cron lib which will be run periodically, but there is a difference between Timer and Cron,
Timer: It's running a task on given specific time intervals whether it is seconds, minutes, or hours.
Cron: It's used for more complex time intervals, eg: if a task needs to be run on a specific time of an hour. let's see the diagram
The above diagram has an asterisk that represents a number that appears in a specific position.
import 'package:cron/cron.dart';
main() {
var cron = new Cron();
cron.schedule(new Schedule.parse('*/3 * * * *'), () async {
print('every three minutes');
});
cron.schedule(new Schedule.parse('8-11 * * * *'), () async {
print('between every 8 and 11 minutes');
});
}
The above examples are taken from the repository which pretty well explains that the first '*' represents minutes, similar for the hour and so on as shown in the diagram.
Another example of the hour would be Schedule.parse(* 1,2,3,4 * * *), This schedule will run every minute every day during the hours of 1 AM, 2 AM, 3 AM, and 4 AM.
for more reference
https://code.tutsplus.com/tutorials/scheduling-tasks-with-cron-jobs--net-8800
Timer works fine, but you can also use Stream to execute a function periodicly:
final Stream _myStream =
Stream.periodic(const Duration(seconds: x), (int count) {
// Do something and return something here
});
see: https://api.flutter.dev/flutter/dart-async/Stream/Stream.periodic.html
I was looking for code to run a function every n amount of seconds for x seconds in total. Also I added functionality to cancel the timer if the periodic Function returns a success before the total timer elapsed. So here is how to solve that:
bool success = false;
bool done = false;
Future.delayed(const Duration(seconds: n), () {
done = true;
print("Timeout");
});
await Stream.periodic(const Duration(seconds: x)).takeWhile((_) => !done).forEach((_) async
{
success = await FunctionYouWantToExecutePeriodicly();
done = success; // only if you want to finish the function earlier
});