Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/async/debouncer.js
2868 views
1
// Copyright 2015 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Definition of the goog.async.Debouncer class.
17
*
18
* @see ../demos/timers.html
19
*/
20
21
goog.provide('goog.async.Debouncer');
22
23
goog.require('goog.Disposable');
24
goog.require('goog.Timer');
25
26
27
28
/**
29
* Debouncer will perform a specified action exactly once for any sequence of
30
* signals fired repeatedly so long as they are fired less than a specified
31
* interval apart (in milliseconds). Whether it receives one signal or multiple,
32
* it will always wait until a full interval has elapsed since the last signal
33
* before performing the action.
34
* @param {function(this: T, ...?)} listener Function to callback when the
35
* action is triggered.
36
* @param {number} interval Interval over which to debounce. The listener will
37
* only be called after the full interval has elapsed since the last signal.
38
* @param {T=} opt_handler Object in whose scope to call the listener.
39
* @constructor
40
* @struct
41
* @extends {goog.Disposable}
42
* @final
43
* @template T
44
*/
45
goog.async.Debouncer = function(listener, interval, opt_handler) {
46
goog.async.Debouncer.base(this, 'constructor');
47
48
/**
49
* Function to callback
50
* @const @private {function(this: T, ...?)}
51
*/
52
this.listener_ =
53
opt_handler != null ? goog.bind(listener, opt_handler) : listener;
54
55
/**
56
* Interval for the debounce time
57
* @const @private {number}
58
*/
59
this.interval_ = interval;
60
61
/**
62
* Cached callback function invoked after the debounce timeout completes
63
* @const @private {!Function}
64
*/
65
this.callback_ = goog.bind(this.onTimer_, this);
66
67
/**
68
* Indicates that the action is pending and needs to be fired.
69
* @private {boolean}
70
*/
71
this.shouldFire_ = false;
72
73
/**
74
* Indicates the count of nested pauses currently in effect on the debouncer.
75
* When this count is not zero, fired actions will be postponed until the
76
* debouncer is resumed enough times to drop the pause count to zero.
77
* @private {number}
78
*/
79
this.pauseCount_ = 0;
80
81
/**
82
* Timer for scheduling the next callback
83
* @private {?number}
84
*/
85
this.timer_ = null;
86
87
/**
88
* When set this is a timestamp. On the onfire we want to reschedule the
89
* callback so it ends up at this time.
90
* @private {?number}
91
*/
92
this.refireAt_ = null;
93
94
/**
95
* The last arguments passed into {@code fire}.
96
* @private {!IArrayLike}
97
*/
98
this.args_ = [];
99
};
100
goog.inherits(goog.async.Debouncer, goog.Disposable);
101
102
103
/**
104
* Notifies the debouncer that the action has happened. It will debounce the
105
* call so that the callback is only called after the last action in a sequence
106
* of actions separated by periods less the interval parameter passed to the
107
* constructor, passing the arguments from the last call of this function into
108
* the debounced function.
109
* @param {...?} var_args Arguments to pass on to the debounced function.
110
*/
111
goog.async.Debouncer.prototype.fire = function(var_args) {
112
this.args_ = arguments;
113
// When this method is called, we need to prevent fire() calls from within the
114
// previous interval from calling the callback. The simplest way of doing this
115
// is to call this.stop() which calls clearTimeout, and then reschedule the
116
// timeout. However clearTimeout and setTimeout are expensive, so we just
117
// leave them untouched and when they do happen we potentially reschedule.
118
this.shouldFire_ = false;
119
if (this.timer_) {
120
this.refireAt_ = goog.now() + this.interval_;
121
return;
122
}
123
this.timer_ = goog.Timer.callOnce(this.callback_, this.interval_);
124
};
125
126
127
/**
128
* Cancels any pending action callback. The debouncer can be restarted by
129
* calling {@link #fire}.
130
*/
131
goog.async.Debouncer.prototype.stop = function() {
132
if (this.timer_) {
133
goog.Timer.clear(this.timer_);
134
this.timer_ = null;
135
}
136
this.refireAt_ = null;
137
this.shouldFire_ = false;
138
this.args_ = [];
139
};
140
141
142
/**
143
* Pauses the debouncer. All pending and future action callbacks will be delayed
144
* until the debouncer is resumed. Pauses can be nested.
145
*/
146
goog.async.Debouncer.prototype.pause = function() {
147
++this.pauseCount_;
148
};
149
150
151
/**
152
* Resumes the debouncer. If doing so drops the pausing count to zero, pending
153
* action callbacks will be executed as soon as possible, but still no sooner
154
* than an interval's delay after the previous call. Future action callbacks
155
* will be executed as normal.
156
*/
157
goog.async.Debouncer.prototype.resume = function() {
158
if (!this.pauseCount_) {
159
return;
160
}
161
162
--this.pauseCount_;
163
if (!this.pauseCount_ && this.shouldFire_) {
164
this.doAction_();
165
}
166
};
167
168
169
/** @override */
170
goog.async.Debouncer.prototype.disposeInternal = function() {
171
this.stop();
172
goog.async.Debouncer.base(this, 'disposeInternal');
173
};
174
175
176
/**
177
* Handler for the timer to fire the debouncer.
178
* @private
179
*/
180
goog.async.Debouncer.prototype.onTimer_ = function() {
181
// There is a newer call to fire() within the debounce interval.
182
// Reschedule the callback and return.
183
if (this.refireAt_) {
184
this.timer_ =
185
goog.Timer.callOnce(this.callback_, this.refireAt_ - goog.now());
186
this.refireAt_ = null;
187
return;
188
}
189
this.timer_ = null;
190
191
if (!this.pauseCount_) {
192
this.doAction_();
193
} else {
194
this.shouldFire_ = true;
195
}
196
};
197
198
199
/**
200
* Calls the callback.
201
* @private
202
*/
203
goog.async.Debouncer.prototype.doAction_ = function() {
204
this.shouldFire_ = false;
205
this.listener_.apply(null, this.args_);
206
};
207
208