[Core] Add throttle service
Add service for throttling function calls; specifically supports reducing tick mark recalculation, WTD-1202.
This commit is contained in:
@@ -180,6 +180,11 @@
|
|||||||
{
|
{
|
||||||
"key": "now",
|
"key": "now",
|
||||||
"implementation": "services/Now.js"
|
"implementation": "services/Now.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "throttle",
|
||||||
|
"implementation": "services/Throttle.js",
|
||||||
|
"depends": [ "$timeout" ]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"roots": [
|
"roots": [
|
||||||
|
|||||||
63
platform/core/src/services/Throttle.js
Normal file
63
platform/core/src/services/Throttle.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throttler for function executions, registered as the `throttle`
|
||||||
|
* service.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* throttle(fn, delay, [apply])
|
||||||
|
*
|
||||||
|
* Returns a function that, when invoked, will invoke `fn` after
|
||||||
|
* `delay` milliseconds, only if no other invocations are pending.
|
||||||
|
* The optional argument `apply` determines whether.
|
||||||
|
*
|
||||||
|
* The returned function will itself return a `Promise` which will
|
||||||
|
* resolve to the returned value of `fn` whenever that is invoked.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
function Throttle($timeout) {
|
||||||
|
/**
|
||||||
|
* Throttle this function.
|
||||||
|
* @param {Function} fn the function to throttle
|
||||||
|
* @param {number} [delay] the delay, in milliseconds, before
|
||||||
|
* executing this function; defaults to 0.
|
||||||
|
* @param {boolean} apply true if a `$apply` call should be
|
||||||
|
* invoked after this function executes; defaults to
|
||||||
|
* `false`.
|
||||||
|
*/
|
||||||
|
return function (fn, delay, apply) {
|
||||||
|
var activeTimeout;
|
||||||
|
|
||||||
|
// Clear active timeout, so that next invocation starts
|
||||||
|
// a new one.
|
||||||
|
function clearActiveTimeout() {
|
||||||
|
activeTimeout = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
delay = delay || 0;
|
||||||
|
apply = apply || false;
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
// Start a timeout if needed
|
||||||
|
if (!activeTimeout) {
|
||||||
|
activeTimeout = $timeout(fn, delay, apply);
|
||||||
|
activeTimeout.then(clearActiveTimeout);
|
||||||
|
}
|
||||||
|
// Return whichever timeout is active (to get
|
||||||
|
// a promise for the results of fn)
|
||||||
|
return activeTimeout;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Throttle;
|
||||||
|
}
|
||||||
|
);
|
||||||
49
platform/core/test/services/ThrottleSpec.js
Normal file
49
platform/core/test/services/ThrottleSpec.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
["../../src/services/Throttle"],
|
||||||
|
function (Throttle) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The 'throttle' service", function () {
|
||||||
|
var throttle,
|
||||||
|
mockTimeout,
|
||||||
|
mockFn,
|
||||||
|
mockPromise;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTimeout = jasmine.createSpy("$timeout");
|
||||||
|
mockPromise = jasmine.createSpyObj("promise", ["then"]);
|
||||||
|
mockFn = jasmine.createSpy("fn");
|
||||||
|
mockTimeout.andReturn(mockPromise);
|
||||||
|
throttle = new Throttle(mockTimeout);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("provides functions which run on a timeout", function () {
|
||||||
|
var throttled = throttle(mockFn);
|
||||||
|
// Verify precondition: Not called at throttle-time
|
||||||
|
expect(mockTimeout).not.toHaveBeenCalled();
|
||||||
|
expect(throttled()).toEqual(mockPromise);
|
||||||
|
expect(mockTimeout).toHaveBeenCalledWith(mockFn, 0, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("schedules only one timeout at a time", function () {
|
||||||
|
var throttled = throttle(mockFn);
|
||||||
|
throttled();
|
||||||
|
throttled();
|
||||||
|
throttled();
|
||||||
|
expect(mockTimeout.calls.length).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("schedules additional invocations after resolution", function () {
|
||||||
|
var throttled = throttle(mockFn);
|
||||||
|
throttled();
|
||||||
|
mockPromise.then.mostRecentCall.args[0](); // Resolve timeout
|
||||||
|
throttled();
|
||||||
|
mockPromise.then.mostRecentCall.args[0]();
|
||||||
|
throttled();
|
||||||
|
expect(mockTimeout.calls.length).toEqual(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"objects/DomainObjectProvider",
|
"objects/DomainObjectProvider",
|
||||||
|
|
||||||
"services/Now",
|
"services/Now",
|
||||||
|
"services/Throttle",
|
||||||
|
|
||||||
"types/MergeModels",
|
"types/MergeModels",
|
||||||
"types/TypeCapability",
|
"types/TypeCapability",
|
||||||
|
|||||||
Reference in New Issue
Block a user