Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is useful for heartbeat-style timeouts where a timeout is reset when certain actions occur. R=lrn@google.com Review URL: https://codereview.chromium.org//1417373004 .
- Loading branch information
Showing
5 changed files
with
164 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
library async.restartable_timer; | ||
|
||
import 'dart:async'; | ||
|
||
/// A non-periodic timer that can be restarted any number of times. | ||
/// | ||
/// Once restarted (via [reset]), the timer counts down from its original | ||
/// duration again. | ||
class RestartableTimer implements Timer { | ||
/// The duration of the timer. | ||
final Duration _duration; | ||
|
||
/// The callback to call when the timer fires. | ||
final ZoneCallback _callback; | ||
|
||
/// The timer for the current or most recent countdown. | ||
/// | ||
/// This timer is canceled and overwritten every time this [RestartableTimer] | ||
/// is reset. | ||
Timer _timer; | ||
|
||
/// Creates a new timer. | ||
/// | ||
/// The [callback] function is invoked after the given [duration]. Unlike a | ||
/// normal non-periodic [Timer], [callback] may be called more than once. | ||
RestartableTimer(this._duration, this._callback) { | ||
_timer = new Timer(_duration, _callback); | ||
} | ||
|
||
bool get isActive => _timer.isActive; | ||
|
||
/// Restarts the timer so that it counts down from its original duration | ||
/// again. | ||
/// | ||
/// This restarts the timer even if it has already fired or has been canceled. | ||
void reset() { | ||
_timer.cancel(); | ||
_timer = new Timer(_duration, _callback); | ||
} | ||
|
||
void cancel() { | ||
_timer.cancel(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:async'; | ||
|
||
import 'package:async/async.dart'; | ||
import 'package:fake_async/fake_async.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
main() { | ||
test("runs the callback once the duration has elapsed", () { | ||
new FakeAsync().run((async) { | ||
var fired = false; | ||
var timer = new RestartableTimer(new Duration(seconds: 5), () { | ||
fired = true; | ||
}); | ||
|
||
async.elapse(new Duration(seconds: 4)); | ||
expect(fired, isFalse); | ||
|
||
async.elapse(new Duration(seconds: 1)); | ||
expect(fired, isTrue); | ||
}); | ||
}); | ||
|
||
test("doesn't run the callback if the timer is canceled", () { | ||
new FakeAsync().run((async) { | ||
var fired = false; | ||
var timer = new RestartableTimer(new Duration(seconds: 5), () { | ||
fired = true; | ||
}); | ||
|
||
async.elapse(new Duration(seconds: 4)); | ||
expect(fired, isFalse); | ||
timer.cancel(); | ||
|
||
async.elapse(new Duration(seconds: 4)); | ||
expect(fired, isFalse); | ||
}); | ||
}); | ||
|
||
test("resets the duration if the timer is reset before it fires", () { | ||
new FakeAsync().run((async) { | ||
var fired = false; | ||
var timer = new RestartableTimer(new Duration(seconds: 5), () { | ||
fired = true; | ||
}); | ||
|
||
async.elapse(new Duration(seconds: 4)); | ||
expect(fired, isFalse); | ||
timer.reset(); | ||
|
||
async.elapse(new Duration(seconds: 4)); | ||
expect(fired, isFalse); | ||
|
||
async.elapse(new Duration(seconds: 1)); | ||
expect(fired, isTrue); | ||
}); | ||
}); | ||
|
||
test("re-runs the callback if the timer is reset after firing", () { | ||
new FakeAsync().run((async) { | ||
var fired = 0; | ||
var timer = new RestartableTimer(new Duration(seconds: 5), () { | ||
fired++; | ||
}); | ||
|
||
async.elapse(new Duration(seconds: 5)); | ||
expect(fired, equals(1)); | ||
timer.reset(); | ||
|
||
async.elapse(new Duration(seconds: 5)); | ||
expect(fired, equals(2)); | ||
timer.reset(); | ||
|
||
async.elapse(new Duration(seconds: 5)); | ||
expect(fired, equals(3)); | ||
}); | ||
}); | ||
|
||
test("runs the callback if the timer is reset after being canceled", () { | ||
new FakeAsync().run((async) { | ||
var fired = false; | ||
var timer = new RestartableTimer(new Duration(seconds: 5), () { | ||
fired = true; | ||
}); | ||
|
||
async.elapse(new Duration(seconds: 4)); | ||
expect(fired, isFalse); | ||
timer.cancel(); | ||
|
||
async.elapse(new Duration(seconds: 4)); | ||
expect(fired, isFalse); | ||
timer.reset(); | ||
|
||
async.elapse(new Duration(seconds: 5)); | ||
expect(fired, isTrue); | ||
}); | ||
}); | ||
|
||
test("only runs the callback once if the timer isn't reset", () { | ||
new FakeAsync().run((async) { | ||
var timer = new RestartableTimer( | ||
new Duration(seconds: 5), | ||
expectAsync(() {}, count: 1)); | ||
async.elapse(new Duration(seconds: 10)); | ||
}); | ||
}); | ||
} |