119 lines
3.8 KiB
HTML
119 lines
3.8 KiB
HTML
|
|
<!--
|
||
|
|
@license
|
||
|
|
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
||
|
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
|
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
|
|
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
|
|
Code distributed by Google as part of the polymer project is also
|
||
|
|
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
|
|
-->
|
||
|
|
<link rel="import" href="boot.html">
|
||
|
|
<link rel="import" href="mixin.html">
|
||
|
|
<link rel="import" href="async.html">
|
||
|
|
|
||
|
|
<script>
|
||
|
|
(function() {
|
||
|
|
'use strict';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @summary Collapse multiple callbacks into one invocation after a timer.
|
||
|
|
* @memberof Polymer
|
||
|
|
*/
|
||
|
|
class Debouncer {
|
||
|
|
constructor() {
|
||
|
|
this._asyncModule = null;
|
||
|
|
this._callback = null;
|
||
|
|
this._timer = null;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Sets the scheduler; that is, a module with the Async interface,
|
||
|
|
* a callback and optional arguments to be passed to the run function
|
||
|
|
* from the async module.
|
||
|
|
*
|
||
|
|
* @param {!AsyncInterface} asyncModule Object with Async interface.
|
||
|
|
* @param {function()} callback Callback to run.
|
||
|
|
* @return {void}
|
||
|
|
*/
|
||
|
|
setConfig(asyncModule, callback) {
|
||
|
|
this._asyncModule = asyncModule;
|
||
|
|
this._callback = callback;
|
||
|
|
this._timer = this._asyncModule.run(() => {
|
||
|
|
this._timer = null;
|
||
|
|
this._callback();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Cancels an active debouncer and returns a reference to itself.
|
||
|
|
*
|
||
|
|
* @return {void}
|
||
|
|
*/
|
||
|
|
cancel() {
|
||
|
|
if (this.isActive()) {
|
||
|
|
this._asyncModule.cancel(this._timer);
|
||
|
|
this._timer = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Flushes an active debouncer and returns a reference to itself.
|
||
|
|
*
|
||
|
|
* @return {void}
|
||
|
|
*/
|
||
|
|
flush() {
|
||
|
|
if (this.isActive()) {
|
||
|
|
this.cancel();
|
||
|
|
this._callback();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Returns true if the debouncer is active.
|
||
|
|
*
|
||
|
|
* @return {boolean} True if active.
|
||
|
|
*/
|
||
|
|
isActive() {
|
||
|
|
return this._timer != null;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Creates a debouncer if no debouncer is passed as a parameter
|
||
|
|
* or it cancels an active debouncer otherwise. The following
|
||
|
|
* example shows how a debouncer can be called multiple times within a
|
||
|
|
* microtask and "debounced" such that the provided callback function is
|
||
|
|
* called once. Add this method to a custom element:
|
||
|
|
*
|
||
|
|
* _debounceWork() {
|
||
|
|
* this._debounceJob = Polymer.Debouncer.debounce(this._debounceJob,
|
||
|
|
* Polymer.Async.microTask, () => {
|
||
|
|
* this._doWork();
|
||
|
|
* });
|
||
|
|
* }
|
||
|
|
*
|
||
|
|
* If the `_debounceWork` method is called multiple times within the same
|
||
|
|
* microtask, the `_doWork` function will be called only once at the next
|
||
|
|
* microtask checkpoint.
|
||
|
|
*
|
||
|
|
* Note: In testing it is often convenient to avoid asynchrony. To accomplish
|
||
|
|
* this with a debouncer, you can use `Polymer.enqueueDebouncer` and
|
||
|
|
* `Polymer.flush`. For example, extend the above example by adding
|
||
|
|
* `Polymer.enqueueDebouncer(this._debounceJob)` at the end of the
|
||
|
|
* `_debounceWork` method. Then in a test, call `Polymer.flush` to ensure
|
||
|
|
* the debouncer has completed.
|
||
|
|
*
|
||
|
|
* @param {Debouncer?} debouncer Debouncer object.
|
||
|
|
* @param {!AsyncInterface} asyncModule Object with Async interface
|
||
|
|
* @param {function()} callback Callback to run.
|
||
|
|
* @return {!Debouncer} Returns a debouncer object.
|
||
|
|
*/
|
||
|
|
static debounce(debouncer, asyncModule, callback) {
|
||
|
|
if (debouncer instanceof Debouncer) {
|
||
|
|
debouncer.cancel();
|
||
|
|
} else {
|
||
|
|
debouncer = new Debouncer();
|
||
|
|
}
|
||
|
|
debouncer.setConfig(asyncModule, callback);
|
||
|
|
return debouncer;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Polymer.Debouncer = Debouncer;
|
||
|
|
})();
|
||
|
|
</script>
|