1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Provides a countdown-based timer implementation.
11 * Constructs a new timer. The timer has a very limited resolution, and does
12 * not attempt to be millisecond accurate. Its intended use is as a
13 * low-precision timer that pauses while debugging.
14 * @param {!SystemTimer} sysTimer The system timer implementation.
15 * @param {number=} timeoutMillis how long, in milliseconds, the countdown
17 * @param {Function=} cb called back when the countdown expires.
19 * @implements {Countdown}
21 function CountdownTimer(sysTimer, timeoutMillis, cb) {
22 /** @private {!SystemTimer} */
23 this.sysTimer_ = sysTimer;
24 this.remainingMillis = 0;
25 this.setTimeout(timeoutMillis || 0, cb);
29 CountdownTimer.TIMER_INTERVAL_MILLIS = 200;
32 * Sets a new timeout for this timer. Only possible if the timer is not
34 * @param {number} timeoutMillis how long, in milliseconds, the countdown lasts.
35 * @param {Function=} cb called back when the countdown expires.
36 * @return {boolean} whether the timeout could be set.
38 CountdownTimer.prototype.setTimeout = function(timeoutMillis, cb) {
41 if (!timeoutMillis || timeoutMillis < 0)
43 this.remainingMillis = timeoutMillis;
45 if (this.remainingMillis > CountdownTimer.TIMER_INTERVAL_MILLIS) {
47 this.sysTimer_.setInterval(this.timerTick.bind(this),
48 CountdownTimer.TIMER_INTERVAL_MILLIS);
50 // Set a one-shot timer for the last interval.
52 this.sysTimer_.setTimeout(
53 this.timerTick.bind(this), this.remainingMillis);
58 /** Clears this timer's timeout. Timers that are cleared become expired. */
59 CountdownTimer.prototype.clearTimeout = function() {
61 this.sysTimer_.clearTimeout(this.timeoutId);
62 this.timeoutId = undefined;
64 this.remainingMillis = 0;
68 * @return {number} how many milliseconds are remaining until the timer expires.
70 CountdownTimer.prototype.millisecondsUntilExpired = function() {
71 return this.remainingMillis > 0 ? this.remainingMillis : 0;
74 /** @return {boolean} whether the timer has expired. */
75 CountdownTimer.prototype.expired = function() {
76 return this.remainingMillis <= 0;
80 * Constructs a new clone of this timer, while overriding its callback.
81 * @param {Function=} cb callback for new timer.
82 * @return {!Countdown} new clone.
84 CountdownTimer.prototype.clone = function(cb) {
85 return new CountdownTimer(this.sysTimer_, this.remainingMillis, cb);
88 /** Timer callback. */
89 CountdownTimer.prototype.timerTick = function() {
90 this.remainingMillis -= CountdownTimer.TIMER_INTERVAL_MILLIS;
92 this.sysTimer_.clearTimeout(this.timeoutId);
93 this.timeoutId = undefined;
101 * A factory for creating CountdownTimers.
102 * @param {!SystemTimer} sysTimer The system timer implementation.
104 * @implements {CountdownFactory}
106 function CountdownTimerFactory(sysTimer) {
107 /** @private {!SystemTimer} */
108 this.sysTimer_ = sysTimer;
112 * Creates a new timer.
113 * @param {number} timeoutMillis How long, in milliseconds, the countdown lasts.
114 * @param {function()=} opt_cb Called back when the countdown expires.
115 * @return {!Countdown} The timer.
117 CountdownTimerFactory.prototype.createTimer =
118 function(timeoutMillis, opt_cb) {
119 return new CountdownTimer(this.sysTimer_, timeoutMillis, opt_cb);
123 * Minimum timeout attenuation, below which a response couldn't be reasonably
124 * guaranteed, in seconds.
127 var MINIMUM_TIMEOUT_ATTENUATION_SECONDS = 1;
130 * @param {number} timeoutSeconds Timeout value in seconds.
131 * @param {number=} opt_attenuationSeconds Attenuation value in seconds.
132 * @return {number} The timeout value, attenuated to ensure a response can be
133 * given before the timeout's expiration.
135 function attenuateTimeoutInSeconds(timeoutSeconds, opt_attenuationSeconds) {
136 var attenuationSeconds =
137 opt_attenuationSeconds || MINIMUM_TIMEOUT_ATTENUATION_SECONDS;
138 if (timeoutSeconds < attenuationSeconds)
140 return timeoutSeconds - attenuationSeconds;
144 * Default request timeout when none is present in the request, in seconds.
147 var DEFAULT_REQUEST_TIMEOUT_SECONDS = 30;
150 * Gets the timeout value from the request, if any, substituting
151 * opt_defaultTimeoutSeconds or DEFAULT_REQUEST_TIMEOUT_SECONDS if the request
152 * does not contain a timeout value.
153 * @param {Object} request The request containing the timeout.
154 * @param {number=} opt_defaultTimeoutSeconds
155 * @return {number} Timeout value, in seconds.
157 function getTimeoutValueFromRequest(request, opt_defaultTimeoutSeconds) {
158 var timeoutValueSeconds;
159 if (request.hasOwnProperty('timeoutSeconds')) {
160 timeoutValueSeconds = request['timeoutSeconds'];
161 } else if (request.hasOwnProperty('timeout')) {
162 timeoutValueSeconds = request['timeout'];
163 } else if (opt_defaultTimeoutSeconds !== undefined) {
164 timeoutValueSeconds = opt_defaultTimeoutSeconds;
166 timeoutValueSeconds = DEFAULT_REQUEST_TIMEOUT_SECONDS;
168 return timeoutValueSeconds;
172 * Creates a new countdown for the given timeout value, attenuated to ensure a
173 * response is given prior to the countdown's expiration, using the given timer
175 * @param {CountdownFactory} timerFactory The factory to use.
176 * @param {number} timeoutValueSeconds
177 * @param {number=} opt_attenuationSeconds Attenuation value in seconds.
178 * @return {!Countdown} A countdown timer.
180 function createAttenuatedTimer(timerFactory, timeoutValueSeconds,
181 opt_attenuationSeconds) {
182 timeoutValueSeconds = attenuateTimeoutInSeconds(timeoutValueSeconds,
183 opt_attenuationSeconds);
184 return timerFactory.createTimer(timeoutValueSeconds * 1000);