Understanding Future.delayed() - dart

When I try to run the below code, it completes in a little more than 4 seconds. I couldn't understand why it finishes in that time. I thought it would complete in 14 seconds(4sec in declaring order variable,10sec in for loop). Don't Future.delayed() stop all the progress in program?
Future<void> printOrderMessage() async {
print("Awaiting user order ...");
var order = await fetchUserOrder(); //I couldn't understand here.
print('Your order is: $order');
}
Future<String> fetchUserOrder() {
return Future.delayed(const Duration(seconds: 4), () => 'Large Latte');
}
void main() async {
countSeconds(4); //Başlama yeri
await printOrderMessage();
}
void countSeconds(int s) {
for (var i = 1; i <= s; i++) {
Future.delayed(Duration(seconds: i), () => print(i)); //Also here
}
}
Output:
Awaiting user order ...
1
2
3
4
Your order is: Large Latte

Related

Error thrown from Future.wait() is not caught in a try-catch block

I am failing to understand, why the error thrown from addItem method in below code is not caught in the try-catch block
void main() async {
var executor = Executor();
var stream = Stream.fromIterable([0, 1, 2, 3, 4, 5, 6, 7]);
try {
await for (var _ in stream) {
executor.submit(() => demoMethod());
}
await executor.execute();
} catch (e) {
print(e);
}
}
Future<void> demoMethod() async {
var list = [1, 2, 3, 1, 4, 5];
var executor = Executor();
var test = Test();
for (var element in list) {
executor.submit(() => test.addItem(element));
}
await executor.execute();
test.list.forEach(print);
}
class Test {
var list = <int>[];
Future<void> addItem(int i) async {
if (list.contains(i)) {
throw Exception('Item exists');
}
list.add(i);
}
}
class Executor {
final List<Future<void>> _futures = [];
bool _disposed = false;
void submit(Future<void> Function() computation) {
if (!_disposed) {
_futures.add(computation());
} else {
throw Exception('Executor is already disposed');
}
}
Future<void> execute() async {
await Future.wait(_futures, eagerError: true);
_disposed = true;
}
}
but below code is able to catch the error properly
void main() async {
var executor = Executor();
try {
for (var i = 0; i < 10; i++) {
executor.submit(() => demoMethod());
}
await executor.execute();
} catch (e) {
print(e);
}
}
I am guessing it has something to do with the stream processing.
It's the stream.
In your other examples, you synchronously run through a loop a and call Executor.submit with all the computations, then immediately call executor.execute().
There is no asychronous gap between calling the function which returns a future, and Future.wait starting to wait for that future.
In the stream code, each stream events starts an asynchronous computation by calling Executor.submit. That creates a future, stores it in a list, and goes back to waiting for the stream.
If that future completes, with an error, before the stream ends and Future.wait gets called, then there is no error handler attached to the future yet. The error is then considered unhandled, and is reported to the current Zone's uncaught error handler. Here that's the root zone, which means it's a global uncaught error, which may crash your entire program.
You need to make sure the future doesn't consider its error unhandled.
The easiest way to do that is to change submit to:
void submit(Future<void> Function() computation) {
if (!_disposed) {
_futures.add(computation()..ignore());
} else {
throw StateError('Executor is already disposed');
}
}
The ..ignore() tells the future that it's OK to not have an error handler.
You know, because the code will later come back and call executor.execute, that any errors will still be reported, so it should be safe to just postpone them a little. That's what Future.ignore is for.
(Also changed Exception to StateError, because that's what you should use to report people using objects that have been disposed or otherwise decommissioned.)

Dart avait Future, postpone just certain line of code and execute the rest

Want to have certain lines of code postponed, using await Future for it and it works great, problem is that it postpones all the code after it, I need it to postpone just certain line of code while continuing to execute rest of the code imediately
void main() async {
for (int i = 0; i < 5; i++) {
await Future.delayed(Duration(seconds: 1));
//postpone just next line or few lines of code
print('postpone this line of code ${i + 1}');
print('postpone me too');
}
//should execute without being postponed
print('continue imediately without being postponed by await Future');
}
Is this possible with await Future or with some other function?
await it syntactic sugar for registering a Future.then callback. The point of using await is to make it easier to make all of the subsequent code wait for the Future to complete. If that's not what you want, you can use Future.then directly:
void main() {
for (int i = 0; i < 5; i++) {
Future.delayed(const Duration(seconds: 1)).then((_) {
print('postpone this line of code ${i + 1}');
print('postpone me too');
});
}
print('continue immediately without being postponed by await Future');
}
Since Future.delayed takes a callback, you can also skip the then completely:
void main() {
for (int i = 0; i < 5; i++) {
Future.delayed(const Duration(seconds: 1), () {
print('postpone this line of code ${i + 1}');
print('postpone me too');
});
}
print('continue immediately without being postponed by await Future');
}
If you don't use the created future for anything, this is equivalent to using a Timer:
import 'dart:async' show Timer;
void main() {
for (int i = 0; i < 5; i++) {
Timer(const Duration(seconds: 1), () {
print('postpone this line of code ${i + 1}');
print('postpone me too');
});
}
print('continue immediately without being postponed by await Future');
}

Dart program exits without executing last statement

I'm trying to understand Streams and wrote some code.
Everything seems to work, the program exits with status code 0. But it doesn't print the 'loop done' and 'main done' strings. I can't figure out why.
import 'dart:async';
Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
yield i;
}
}
class Retry {
StreamController<int> _outgoing;
Retry(Stream<int> incoming) {
_outgoing = StreamController<int>();
_outgoing.addStream(incoming);
}
Future<void> process() async {
await for (final i in _outgoing.stream) {
print("got $i");
}
print('loop done'); // Not printed
}
}
void main() async {
var stream = countStream(4);
var retry = Retry(stream);
await retry.process();
print('main done'); // Not printed
}
The _outgoing.stream is never closed, so code after the await for will never execute. The VM does notice that there also won't be any new events on that stream so nothing else will ever happen, and it can exit. You could fix the bug with:
_outgoing.addStream(incoming).whenComplete(() {
_outgoing.close();
});

Difference between await for and listen in Dart

I am trying to create a web server stream. Here is the code:
import 'dart:io';
main() async {
HttpServer requestServer = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 8000);
requestServer.listen((request) { //comment out this or the await for to work
request.response
..write("This is a listen stream")
..close();
});
await for (HttpRequest request in requestServer) {
request.response
..write("This is an await for stream")
..close();
}
}
What is the difference between listen and await for? They both do not work at the same time. You need to comment out one or the other to work, but there doesn't seem to be a difference in function here. Are there circumstances where there is a difference, and when should you use one over the other?
Given:
Stream<String> stream = new Stream<String>.fromIterable(['mene', 'mene', 'tekel', 'parsin']);
then:
print('BEFORE');
stream.listen((s) { print(s); });
print('AFTER');
yields:
BEFORE
AFTER
mene
mene
tekel
parsin
whereas:
print('BEFORE');
await for(String s in stream) { print(s); }
print('AFTER');
yields:
BEFORE
mene
mene
tekel
parsin
AFTER
stream.listen() sets up code that will be put on the event queue when an event arrives, then following code is executed.
await for suspends between events and keeps doing so until the stream is done, so code following it will not be executed until that happens.
I use `await for when I have a stream that I know will have finite events, and I need to process them before doing anything else (essentially as if I'm dealing with a list of futures).
Check https://www.dartlang.org/articles/language/beyond-async for a description of await for.
The main difference is when there's code afterwards. listen only register the handler and the execution continue. await for will retain execution until the stream is closed.
Thus if you add a print('hello'); at the end of your main you shouldn't see hello in the output with await for (because the request stream is never closed). Try the following code on dartpad to see the differences :
import 'dart:async';
main() async {
tenInts.listen((i) => print('int $i'));
//await for (final i in tenInts) {
// print('int $i');
//}
print('hello');
}
Stream<int> get tenInts async* {
for (int i = 1; i <= 10; i++) yield i;
}
A more imporant difference is that await for serializes the consumption of the stream items while listen will process them concurrently.
For example the code below:
import 'dart:async';
Future<void> process(int i) async {
print("start $i");
await new Future.delayed(const Duration(seconds: 1));
print("end $i");
}
main() async {
await for (final i in tenInts) {
await process(i);
}
tenInts.listen((i) async => await process(i));
print('hello');
}
Stream<int> get tenInts async* {
for (int i = 1; i <= 10; i++) yield i;
}
yields
start 1
end 1
start 2
end 2
start 3
end 3
start 4
end 4
start 5
end 5
start 6
end 6
start 7
end 7
start 8
end 8
start 9
end 9
start 10
end 10
hello
start 1
start 2
start 3
start 4
start 5
start 6
start 7
start 8
start 9
start 10
end 1
end 2
end 3
end 4
end 5
end 6
end 7
end 8
end 9
end 10
Another difference can be the listen() returns you a StreamSubscription object, which can be used to cancel/pause the subscription at any later point of time. You can set callbacks to be called for each data event or error event, and when the stream is closed.
The below demonstrates that after listening to stream for 5 seconds, we will cancel it.
Stream<int> gen() async* {
for (int i = 1; i <= 10; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
print("done");
}
main() async {
Stream<int> stream = gen();
var subscription = stream.listen((item){
print(item);
});
await Future.delayed(Duration(seconds: 5));
subscription.cancel();
print("Exit");
}
Output:
1
2
3
4
Exit
As Robson said:
await for serializes the consumption of the stream items while listen
will process them concurrently.
I would also like to add a note that while use listen method possible to process stream events one by one if use pause and resume methods.
Pause method should be called before first await keyword.
StreamSubscription<int> subscription;
subscription = tenInts.listen((i) async {
subscription.pause();
await process(i);
subscription.resume();
});
Future<void> process(int i) async {
print("start $i");
await new Future.delayed(const Duration(seconds: 1));
print("end $i");
}

How to delete a Dart future when it's no longer needed

This is related to is there any way to cancel a dart Future?
In my case, there are no HTTP, just expensive calculations. I have a table/list which I scroll through. As the elements become visible, I generate futures to show the calculation results. But if I (the end user) scroll quickly, some results will have "scrolled out of view" and will no longer required. This could be a large number, and would seriously delay the return of futures (results) that are to be usefully :-) displayed in currently visible elements. Can something be done about that? cheers, Steve
You could just set a flag which indicates to the delayed code (run from futures) that the result isn't needed anymore.
When the delayed code is called it just returns.
library cancel_future;
import 'dart:async' show Future, Timer;
import 'dart:math' show Random;
typedef void TaskFunction(Task task);
// Container for a task
class Task {
// an assigned task id
final id;
// data to process
int data;
// Indicate to the task function, that it should stop processing
bool isCanceled = false;
// The task function must set this flat to true when all work is done.
bool isFinished = false;
// The task function which processed the data and sets the result.
TaskFunction fn;
// The result set by the task function when it finished processing.
int result;
Task(this.id, this.data, this.fn);
// Start processing the task.
void execute() => fn(this);
}
final rnd = new Random();
void main(List<String> args) {
// create tasks
final tasks = new List<Task>.from(generate());
// start all tasks
tasks.forEach((t) => t.execute());
// after random delay cancel all unfinished tasks
new Future.delayed(new Duration(seconds: rnd.nextInt(10)), () {
tasks.forEach((t) {
if (!t.isFinished) {
t.isCanceled = true;
}
});
}).then((_) {
// check results
int done = 0;
int canceled = 0;
tasks.forEach((t) {
print(
'Task id: ${t.id}; isCanceled: ${t.isCanceled}; isFinished: ${t.isFinished}; data: ${t.data}; result: ${t.result}');
if (t.isFinished) {
done++;
}
if (t.isCanceled) {
canceled++;
}
});
print('Canceled: $canceled.');
print('Done: $done.');
});
}
// geneator for job 100 jobs
Iterable<Task> generate() sync* {
int i = 0;
while (i++ < 100) {
yield new Task(i, rnd.nextInt(100), calc);
}
}
// job function
void calc(Task t) {
// do a bit of work every 100ms to simulate longer processing
new Timer.periodic(new Duration(milliseconds: 100), (timer) {
var result = 0;
// check if jost was canceled and stop processing in case it was.
if (t.isCanceled) {
timer.cancel();
return;
}
// while not finished do a chunk of work
if (result < t.data) {
result++;
} else {
// finished - clean up and store result
t.isFinished = true;
t.result = result;
timer.cancel();
}
});
}

Resources