I'd like to run a function over and over, with a delay in between. How can I do this with Dart?
You can use the Timer class to schedule one-shot and repeating functions.
Repeating
Here is how you run a repeating function:
import 'dart:async';
main() {
const oneSec = Duration(seconds:1);
Timer.periodic(oneSec, (Timer t) => print('hi!'));
}
The Timer takes two arguments, a duration and a function to run. The duration must be an instance of Duration. The callback must take a single parameter, the timer itself.
Canceling a repeating timer
Use timer.cancel() to cancel a repeating timer. This is one reason why timer is passed to the callback run from a repeating timer.
One-shot after a delay
To schedule a one-shot function after a delay (execute once, some time in the future):
import 'dart:async';
main() {
const twentyMillis = Duration(milliseconds:20);
Timer(twentyMillis, () => print('hi!'));
}
Notice the callback for a one-shot timer does not take a parameter.
One-shot as soon as possible
You can also request that a function is run as soon as possible, at least one event-loop tick in the future.
import 'dart:async';
main() {
Timer.run(() => print('hi!'));
}
In HTML
Timers even work in HTML. In fact, window.setTimeout was removed, so Timer is the only way to run a function in the future.
5 Sec Timer Example
bool isStopped = false; //global
sec5Timer() {
Timer.periodic(Duration(seconds: 5), (timer) {
if (isStopped) {
timer.cancel();
}
print("Dekhi 5 sec por por kisu hy ni :/");
});
}
Call from any function
sec5Timer();
Stop from any function
isStopped = true;
To dispose you can use this code or technique.
#override
void initState() {
_timer = new Timer.periodic(widget.refreshRate,
(Timer timer) => _updateDisplayTime(inheritedWidget));
super.initState();
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
https://api.dartlang.org/stable/1.24.3/dart-async/Stream/Stream.periodic.html
import 'dart:async';
StreamSubscription periodicSub;
void main() {
periodicSub = new Stream.periodic(const Duration(milliseconds: 500), (v) => v)
.take(10)
.listen((count) => print('tick $count'));
}
or if the counter isn't required just
import 'dart:async';
StreamSubscription periodicSub;
void main() {
periodicSub = new Stream.periodic(const Duration(milliseconds: 500))
.take(10)
.listen((_) => print('tick'));
}
You can also use Future.delayed and await to delay execution:
Future<Null> delay(int milliseconds) {
return new Future.delayed(new Duration(milliseconds: milliseconds));
}
main() async {
await delay(500);
print('Delayed 500 milliseconds');
}
alternative;
import 'dart:async';
Timer interval(Duration duration, func) {
Timer function() {
Timer timer = new Timer(duration, function);
func(timer);
return timer;
}
return new Timer(duration, function);
}
void main() {
int i = 0;
interval(new Duration(seconds: 1), (timer) {
print(i++);
if (i > 5) timer.cancel();
});
}
Opposite to Timer.periodic and Stream.periodic posting my favorite way to handle such a tasks. The advantages:
the first cycle run instantly
the callback can work longer than
interval without any reentrance headache
Completer<bool> periodic(Duration interval, Function(int cycle) callback) {
final done = Completer<bool>();
() async {
var cycle = 0;
while (!done.isCompleted) {
try {
await callback(cycle);
} catch (e, s) {
log("$e", stackTrace: s);
}
cycle++;
await done.future
.timeout(interval)
.onError((error, stackTrace) => null);
}
}();
return done;
}
main() {
final task = periodic(Duration(seconds: 10), (cycle) async {
/// do the periodic tasks here
});
/// main code here
/// and when going to stop the above periodic call
task.complete(true);
}
Functionally identical code to JavaScript (setInterval, setTimeout, clearInterval and clearTimeout):
// ------------------------------
// Import:
import 'dart:async';
// ------------------------------
// Definitions:
void clearTimeout(Timer timer) {
try {
timer.cancel();
} catch (e) {}
}
Timer setTimeout(VoidCallback fn, int millis) {
Timer timer;
if (millis > 0)
timer = new Timer(new Duration(milliseconds: millis), fn);
else
fn();
return timer;
}
void clearInterval(Timer timer) {
try {
timer.cancel();
} catch (e) {}
}
Timer setInterval(VoidCallback fn, int millis) {
Timer timer;
if (millis > 0)
timer = new Timer.periodic(new Duration(milliseconds: millis), (timer) {
fn();
});
else
fn(); // If millis input is too low, only run function once and stop
return timer;
}
// ---------------------------------
// Example:
int myValue = 0;
Timer counter = setInterval((){ myValue++; }, 50);
setTimeout((){
clearInterval(counter);
}, 5000);
Related
I am trying to pass data (bool) from a child class through a callback Function (ondone) provided by the parent class, which will be called in a periodic function with a boolean argument.
import 'dart:async';
class Flow {
MyTimer timer;
bool done = false;
Function ondone;
Flow() {
ondone = (bool b) => done=b;
}
void addtimer(int t) {
timer = MyTimer(t, ondone);
}
}
class MyTimer {
final int time;
int remaining;
Function callback;
Timer _timer;
MyTimer(this.time, this.callback){
remaining = time;
}
void run() {
_timer = Timer.periodic(
Duration(seconds: 1),
(t) {
remaining--;
if (remaining == 0) {
_timer.cancel();
callback(true);
}
});
}
}
But I am unable to figure out if callback is being called or not, because print function (in main) is not printing anything which is wrapped in an if expression.
void main() {
var flow=Flow();
flow.addtimer(5);
flow.timer.run();
if(flow.done) print('Timer Finished..');
print('I need to run while timer is working');
}
Passing data from child to parent in an imperative style is important for me (as a beginner).
The call to flow.timer.run() invokes the Timer which executes asynchronously. Your next line of code tests flow.done immediately, and of course it is not done yet. If you do this:
flow.timer.run();
await Future.delayed(Duration(seconds: 6));
if (flow.done) print('Timer Finished..');
Then your main function will pause for 6 seconds by which time the Timer will be complete.
If you do want to wait for the delay, you could code as follows:
Future<void> run() async {
while (remaining > 0) {
await Future.delayed(Duration(seconds: 1));
remaining = remaining - 1;
}
callback(true);
}
and call it as:
await flow.timer.run();
Edit: If you want to run other code in main and then wait, you can do:
var future = flow.timer?.run();
print('Timer is running...');
await future;
if (flow.done) print('Timer Finished..');
When adding async* to listen method it isn't executing the function body
import 'dart:async';
main(List<String> args) {
print('====');
tranStream();
}
Stream<int> intStreamer() async* {
int c = 0;
while (c <= 30) {
await Future.delayed(Duration(seconds: 1));
yield c++;
}
}
tranStream() {
intStreamer().listen((event) async* { // If i remove async* from here it will execute print statement
print(event);
});
}
If i remove async* from intStreamer().listen it will execute print statement. What is happening here?
When you are using async*, the method will only start being executed when the returned Stream gets a subscriber. Your code does not really make any sense since listen takes a method which returns void. So nobody are going to listen on the returned Stream which the given method will automatically return (based on the async* keyword).
I would also properly rewrite your code so you instead of listen uses await for which I think makes it more clear what happens`:
import 'dart:async';
Future<void> main(List<String> args) async {
print('====');
await tranStream();
}
Stream<int> intStreamer() async* {
int c = 0;
while (c <= 30) {
await Future<void>.delayed(const Duration(seconds: 1));
yield c++;
}
}
Future<void> tranStream() async {
await for (final event in intStreamer()) {
print(event);
}
}
Update with example of tranStream returns a Stream:
import 'dart:async';
Future<void> main(List<String> args) async {
print('====');
await for (final event in tranStream()) {
print('main got: $event');
}
}
Stream<int> intStreamer() async* {
int c = 0;
while (c <= 30) {
await Future<void>.delayed(const Duration(seconds: 1));
yield c++;
}
}
Stream<int> tranStream() async* {
await for (final event in intStreamer()) {
print('tranStream got: $event');
yield event;
}
}
import 'dart:io';
void main() {
performTask();
}
void performTask() {
task1();
task2();
task3();
}
void task1() {
print('task1');
}
void task2() {
Duration timeDuration = Duration(seconds: 3);
sleep(timeDuration);
print('task2');
}
void task3() {
print('task3');
}
After executing first function that is task1() it throws an error:
Uncaught Error: Unsupported operation: ProcessUtils._sleep
I just hit the same roadblock! Not sure how to get sleep to work, but i found that using async/await is a bit more predictable:
// Unused import
// import 'dart:io'; // Delete me
void main() {
performTask();
}
// No need for async/await here, just the method in which it's used to await Future.delayed
void performTask() {
task1();
task2();
task3();
}
void task1() {
print('task1');
}
// I'm still a bit new to flutter, but as I understand it, best practice is to use Future<T> myFunction() {...} when defining async/await method.
// In this case <T> is <void> because you're not returning anything!
Future<void> task2() async {
Duration timeDuration = Duration(seconds: 3);
// sleep(timeDuration) // Delete Me
await Future.duration(timeDuration); // replacement for the sleep method, comes from the 'package:flutter/material.dart'
print('task2');
}
void task3() {
print('task3');
}
Credit: How can I "sleep" a Dart program
Since Future.duration doesn't
await Future.delayed(const Duration(seconds: 1));
credit: How can I "sleep" a Dart program
In Python there is a function called Time.Sleep () to pause the execution of a period of time, some alternative in Vala.
What I try to do is execute a While (True) but the content is executed in a certain period of time, for example 5 seconds.
Maybe have a look at the async example here:
// Build with: valac --pkg=gio-2.0 example.vala
public async void nap (uint interval, int priority = GLib.Priority.DEFAULT) {
GLib.Timeout.add (interval, () => {
nap.callback ();
return false;
}, priority);
yield;
}
private async void do_stuff () {
yield nap (1000);
}
private static int main (string[] args) {
GLib.MainLoop loop = new GLib.MainLoop ();
do_stuff.begin ((obj, async_res) => {
loop.quit ();
});
loop.run ();
return 0;
}
https://wiki.gnome.org/Projects/Vala/AsyncSamples
I think I understand the idea behind async, returning a Future, but I am not clear on how async behaves on a very basic level. From my understanding, it does not automatically create asynchronous behavior in a program. For example:
import 'dart:async';
main() {
a();
b();
}
a() {
new Timer(new Duration(milliseconds: 20), () {}); // create latency
print("a");
}
b() {
print("b");
}
// a
// b
If you put async after the a(), the b() is executed first asynchronously, and a() executes after the given latency:
import 'dart:async';
main() {
a();
b();
}
a() **async** {
new Timer(new Duration(milliseconds: 20), () {}); // create latency
print("a");
}
b() {
print("b");
}
// b
// a
But if you put async after both a() and b(), a() executes first, similar to not using async at all:
import 'dart:async';
main() {
a();
b();
}
a() **async** {
new Timer(new Duration(milliseconds: 20), () {}); // create latency
print("a");
}
b() **async** {
print("b");
}
//a
//b
Is using async on all functions cancelling the async function completely?
Now, I think that the main() async does not actually activate the asynchronous behavior by itself. If you add async after the main(), nothing changes. However, it allows for you to use await, in case you must wait for the a() function to finish first, before you continue the program. Is this right?
import 'dart:async';
main() **async** {
**await** a();
b();
}
a() **async** {
new Timer(new Duration(milliseconds: 20), () {}); // create latency
print("a");
}
b() {
print("b");
}
// waits for the value of a() if you put **await** keyword
// a
// b
However, I see main() async {} alot as well as using it after the script html tag, yet there is no await anywhere. Does it mean different things in different contexts? I hope I have explained the logic adequately. Can you explain how I am misunderstanding the use of async/await? Thank you.
a() {
new Timer(new Duration(milliseconds: 20), () {}); // create latency
print("a");
}
This code doesn't delay execution of print("a"); for 20 ms. It just delays the execution of {} which is enqueued for later execution, and then immediately continued with print("a");
Your code using async / await and the equivalent code without async / await would look like:
import 'dart:async';
main() async {
await a();
b();
await main2(); // call the example without async/await
}
Future a() async {
await new Future.delayed(const Duration(milliseconds: 20), () {}); // create latency
print("a");
}
void b() {
print("b");
}
Future main2() {
return a2().then((_) {
b();
});
}
// equivalent of a without async/await
Future a2() {
return new Future.delayed(const Duration(milliseconds: 20), () {}) // create latency
.then((_) => print("a"));
}
Try on DartPad