如何在 Dart 中运行重现函数?

我希望一遍又一遍地运行一个函数,中间有一个延迟。我怎么能和达特一起做这个?

95453 次浏览

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.

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');
}

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'));
}

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();
});
}

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();
}

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);

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);
}