foop
Version:
interfaces that describe their intentions.
137 lines (131 loc) • 12.4 kB
JavaScript
var isObj = require('../is/obj')
var isIn = require('../is/in')
var noop = require('../util/noop')
var toBoolean = require('../cast/toBoolean')
var debounce = require('./debounce')
/**
* - Returns a function, that, when invoked, will only be triggered at most once
* during a given window of time. Normally, the throttled function will run
* as much as it can, without ever going more than once per `wait` duration;
* but if you'd like to disable the execution on the leading edge, pass
* `{leading: false}`. To disable execution on the trailing edge, ditto.
* - Creates a throttled function that only invokes `func` at most once per
* every `wait` milliseconds. The throttled function comes with a `cancel`
* method to cancel delayed `func` invocations and a `flush` method to
* immediately invoke them. Provide `options` to indicate whether `func`
* should be invoked on the leading and/or trailing edge of the `wait`
* timeout. The `func` is invoked with the last arguments provided to the
* throttled function. Subsequent calls to the throttled function return the
* result of the last `func` invocation.
*
* @NOTE If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the throttled function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* @since 5.0.0-beta.1
*
* @param {Function} func The function to throttle.
* @param {number} [wait=0] The number of milliseconds to throttle invocations to.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.leading=true]
* Specify invoking on the leading edge of the timeout.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @return {Function} Returns the new throttled function.
*
* @fork 0.1.0
* @category Function
*
* {@link https://github.com/andrewplummer/Sugar/blob/master/lib/function.js#L172 sugar-throttle}
* {@link https://github.com/lodash/lodash/blob/master/throttle.js lodash-throttle}
* {@link https://css-tricks.com/debouncing-throttling-explained-examples/ debounce-vs-throttle-difference-explained}
* @see {@link debounce-vs-throttle-difference-explained}
* @see {@link lodash-throttle}
* @see {@link sugar-throttle}
*
* @example
*
* // Avoid excessively updating the position while scrolling.
* jQuery(window).on('scroll', throttle(updatePosition, 100))
*
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
* const throttled = throttle(renewToken, 300000, { 'trailing': false })
* jQuery(element).on('click', throttled)
*
* // Cancel the trailing throttled invocation.
* jQuery(window).on('popstate', throttled.cancel)
*
*/
module.exports = function throttle(func, wait, options) {
var leading = true
var trailing = true
if (typeof func !== 'function') {
func = noop
// throw new TypeError('Expected a function')
}
if (isObj(options)) {
leading = isIn(options, 'leading')
? toBoolean(options.leading)
: leading
trailing = isIn(options, 'trailing')
? toBoolean(options.trailing)
: trailing
}
return debounce(func, wait, {
'leading': leading,
'maxWait': wait,
'trailing': trailing,
})
}
// is underscore.js version
// function(func, wait, options = {}) {
// let timeout
// let thisArg
// let args
// let result
// let previous = 0
//
// const later = function() {
// previous = options.leading === false ? 0 : Date.now()
// timeout = null
// result = func.apply(thisArg, args)
// if (!timeout) thisArg = args = null
// }
//
// const throttled = function() {
// const now = Date.now()
// if (!previous && options.leading === false) previous = now
//
// const remaining = wait - (now - previous)
// thisArg = this
// args = arguments
//
// if (remaining <= 0 || remaining > wait) {
// if (timeout) {
// clearTimeout(timeout)
// timeout = null
// }
//
// previous = now
// result = func.apply(thisArg, args)
//
// if (!timeout) thisArg = args = null
// }
// else if (!timeout && options.trailing !== false) {
// timeout = setTimeout(later, remaining)
// }
// return result
// }
//
// throttled.cancel = function() {
// clearTimeout(timeout)
// previous = 0
// timeout = thisArg = args = null
// }
//
// return throttled
// }
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyb3R0bGUuanMiLCJzb3VyY2VzIjpbInRocm90dGxlLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IGlzT2JqID0gcmVxdWlyZSgnLi4vaXMvb2JqJylcbmNvbnN0IGlzSW4gPSByZXF1aXJlKCcuLi9pcy9pbicpXG5jb25zdCBub29wID0gcmVxdWlyZSgnLi4vdXRpbC9ub29wJylcbmNvbnN0IHRvQm9vbGVhbiA9IHJlcXVpcmUoJy4uL2Nhc3QvdG9Cb29sZWFuJylcbmNvbnN0IGRlYm91bmNlID0gcmVxdWlyZSgnLi9kZWJvdW5jZScpXG5cbi8qKlxuICogLSBSZXR1cm5zIGEgZnVuY3Rpb24sIHRoYXQsIHdoZW4gaW52b2tlZCwgd2lsbCBvbmx5IGJlIHRyaWdnZXJlZCBhdCBtb3N0IG9uY2VcbiAqIGR1cmluZyBhIGdpdmVuIHdpbmRvdyBvZiB0aW1lLiBOb3JtYWxseSwgdGhlIHRocm90dGxlZCBmdW5jdGlvbiB3aWxsIHJ1blxuICogYXMgbXVjaCBhcyBpdCBjYW4sIHdpdGhvdXQgZXZlciBnb2luZyBtb3JlIHRoYW4gb25jZSBwZXIgYHdhaXRgIGR1cmF0aW9uO1xuICogYnV0IGlmIHlvdSdkIGxpa2UgdG8gZGlzYWJsZSB0aGUgZXhlY3V0aW9uIG9uIHRoZSBsZWFkaW5nIGVkZ2UsIHBhc3NcbiAqIGB7bGVhZGluZzogZmFsc2V9YC4gVG8gZGlzYWJsZSBleGVjdXRpb24gb24gdGhlIHRyYWlsaW5nIGVkZ2UsIGRpdHRvLlxuICogLSBDcmVhdGVzIGEgdGhyb3R0bGVkIGZ1bmN0aW9uIHRoYXQgb25seSBpbnZva2VzIGBmdW5jYCBhdCBtb3N0IG9uY2UgcGVyXG4gKiBldmVyeSBgd2FpdGAgbWlsbGlzZWNvbmRzLiBUaGUgdGhyb3R0bGVkIGZ1bmN0aW9uIGNvbWVzIHdpdGggYSBgY2FuY2VsYFxuICogbWV0aG9kIHRvIGNhbmNlbCBkZWxheWVkIGBmdW5jYCBpbnZvY2F0aW9ucyBhbmQgYSBgZmx1c2hgIG1ldGhvZCB0b1xuICogaW1tZWRpYXRlbHkgaW52b2tlIHRoZW0uIFByb3ZpZGUgYG9wdGlvbnNgIHRvIGluZGljYXRlIHdoZXRoZXIgYGZ1bmNgXG4gKiBzaG91bGQgYmUgaW52b2tlZCBvbiB0aGUgbGVhZGluZyBhbmQvb3IgdHJhaWxpbmcgZWRnZSBvZiB0aGUgYHdhaXRgXG4gKiB0aW1lb3V0LiBUaGUgYGZ1bmNgIGlzIGludm9rZWQgd2l0aCB0aGUgbGFzdCBhcmd1bWVudHMgcHJvdmlkZWQgdG8gdGhlXG4gKiB0aHJvdHRsZWQgZnVuY3Rpb24uIFN1YnNlcXVlbnQgY2FsbHMgdG8gdGhlIHRocm90dGxlZCBmdW5jdGlvbiByZXR1cm4gdGhlXG4gKiByZXN1bHQgb2YgdGhlIGxhc3QgYGZ1bmNgIGludm9jYXRpb24uXG4gKlxuICogQE5PVEUgSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIHRocm90dGxlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIEBzaW5jZSA1LjAuMC1iZXRhLjFcbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byB0aHJvdHRsZS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBbd2FpdD0wXSBUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB0aHJvdHRsZSBpbnZvY2F0aW9ucyB0by5cbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9ucz17fV0gVGhlIG9wdGlvbnMgb2JqZWN0LlxuICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5sZWFkaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgbGVhZGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy50cmFpbGluZz10cnVlXVxuICogIFNwZWNpZnkgaW52b2tpbmcgb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHRocm90dGxlZCBmdW5jdGlvbi5cbiAqXG4gKiBAZm9yayAwLjEuMFxuICogQGNhdGVnb3J5IEZ1bmN0aW9uXG4gKlxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmRyZXdwbHVtbWVyL1N1Z2FyL2Jsb2IvbWFzdGVyL2xpYi9mdW5jdGlvbi5qcyNMMTcyIHN1Z2FyLXRocm90dGxlfVxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9sb2Rhc2gvbG9kYXNoL2Jsb2IvbWFzdGVyL3Rocm90dGxlLmpzIGxvZGFzaC10aHJvdHRsZX1cbiAqIHtAbGluayBodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvIGRlYm91bmNlLXZzLXRocm90dGxlLWRpZmZlcmVuY2UtZXhwbGFpbmVkfVxuICogQHNlZSB7QGxpbmsgZGVib3VuY2UtdnMtdGhyb3R0bGUtZGlmZmVyZW5jZS1leHBsYWluZWR9XG4gKiBAc2VlIHtAbGluayBsb2Rhc2gtdGhyb3R0bGV9XG4gKiBAc2VlIHtAbGluayBzdWdhci10aHJvdHRsZX1cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqICAgICAvLyBBdm9pZCBleGNlc3NpdmVseSB1cGRhdGluZyB0aGUgcG9zaXRpb24gd2hpbGUgc2Nyb2xsaW5nLlxuICogICAgIGpRdWVyeSh3aW5kb3cpLm9uKCdzY3JvbGwnLCB0aHJvdHRsZSh1cGRhdGVQb3NpdGlvbiwgMTAwKSlcbiAqXG4gKiAgICAgLy8gSW52b2tlIGByZW5ld1Rva2VuYCB3aGVuIHRoZSBjbGljayBldmVudCBpcyBmaXJlZCwgYnV0IG5vdCBtb3JlIHRoYW4gb25jZSBldmVyeSA1IG1pbnV0ZXMuXG4gKiAgICAgY29uc3QgdGhyb3R0bGVkID0gdGhyb3R0bGUocmVuZXdUb2tlbiwgMzAwMDAwLCB7ICd0cmFpbGluZyc6IGZhbHNlIH0pXG4gKiAgICAgalF1ZXJ5KGVsZW1lbnQpLm9uKCdjbGljaycsIHRocm90dGxlZClcbiAqXG4gKiAgICAgLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyB0aHJvdHRsZWQgaW52b2NhdGlvbi5cbiAqICAgICBqUXVlcnkod2luZG93KS5vbigncG9wc3RhdGUnLCB0aHJvdHRsZWQuY2FuY2VsKVxuICpcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiB0aHJvdHRsZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIGxldCBsZWFkaW5nID0gdHJ1ZVxuICBsZXQgdHJhaWxpbmcgPSB0cnVlXG5cbiAgaWYgKHR5cGVvZiBmdW5jICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgZnVuYyA9IG5vb3BcbiAgICAvLyB0aHJvdyBuZXcgVHlwZUVycm9yKCdFeHBlY3RlZCBhIGZ1bmN0aW9uJylcbiAgfVxuICBpZiAoaXNPYmoob3B0aW9ucykpIHtcbiAgICBsZWFkaW5nID0gaXNJbihvcHRpb25zLCAnbGVhZGluZycpXG4gICAgICA/IHRvQm9vbGVhbihvcHRpb25zLmxlYWRpbmcpXG4gICAgICA6IGxlYWRpbmdcblxuICAgIHRyYWlsaW5nID0gaXNJbihvcHRpb25zLCAndHJhaWxpbmcnKVxuICAgICAgPyB0b0Jvb2xlYW4ob3B0aW9ucy50cmFpbGluZylcbiAgICAgIDogdHJhaWxpbmdcbiAgfVxuXG4gIHJldHVybiBkZWJvdW5jZShmdW5jLCB3YWl0LCB7XG4gICAgJ2xlYWRpbmcnOiBsZWFkaW5nLFxuICAgICdtYXhXYWl0Jzogd2FpdCxcbiAgICAndHJhaWxpbmcnOiB0cmFpbGluZyxcbiAgfSlcbn1cblxuLy8gaXMgdW5kZXJzY29yZS5qcyB2ZXJzaW9uXG4vLyBmdW5jdGlvbihmdW5jLCB3YWl0LCBvcHRpb25zID0ge30pIHtcbi8vICAgbGV0IHRpbWVvdXRcbi8vICAgbGV0IHRoaXNBcmdcbi8vICAgbGV0IGFyZ3Ncbi8vICAgbGV0IHJlc3VsdFxuLy8gICBsZXQgcHJldmlvdXMgPSAwXG4vL1xuLy8gICBjb25zdCBsYXRlciA9IGZ1bmN0aW9uKCkge1xuLy8gICAgIHByZXZpb3VzID0gb3B0aW9ucy5sZWFkaW5nID09PSBmYWxzZSA/IDAgOiBEYXRlLm5vdygpXG4vLyAgICAgdGltZW91dCA9IG51bGxcbi8vICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXNBcmcsIGFyZ3MpXG4vLyAgICAgaWYgKCF0aW1lb3V0KSB0aGlzQXJnID0gYXJncyA9IG51bGxcbi8vICAgfVxuLy9cbi8vICAgY29uc3QgdGhyb3R0bGVkID0gZnVuY3Rpb24oKSB7XG4vLyAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKVxuLy8gICAgIGlmICghcHJldmlvdXMgJiYgb3B0aW9ucy5sZWFkaW5nID09PSBmYWxzZSkgcHJldmlvdXMgPSBub3dcbi8vXG4vLyAgICAgY29uc3QgcmVtYWluaW5nID0gd2FpdCAtIChub3cgLSBwcmV2aW91cylcbi8vICAgICB0aGlzQXJnID0gdGhpc1xuLy8gICAgIGFyZ3MgPSBhcmd1bWVudHNcbi8vXG4vLyAgICAgaWYgKHJlbWFpbmluZyA8PSAwIHx8IHJlbWFpbmluZyA+IHdhaXQpIHtcbi8vICAgICAgIGlmICh0aW1lb3V0KSB7XG4vLyAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KVxuLy8gICAgICAgICB0aW1lb3V0ID0gbnVsbFxuLy8gICAgICAgfVxuLy9cbi8vICAgICAgIHByZXZpb3VzID0gbm93XG4vLyAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXNBcmcsIGFyZ3MpXG4vL1xuLy8gICAgICAgaWYgKCF0aW1lb3V0KSB0aGlzQXJnID0gYXJncyA9IG51bGxcbi8vICAgICB9XG4vLyAgICAgZWxzZSBpZiAoIXRpbWVvdXQgJiYgb3B0aW9ucy50cmFpbGluZyAhPT0gZmFsc2UpIHtcbi8vICAgICAgIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGxhdGVyLCByZW1haW5pbmcpXG4vLyAgICAgfVxuLy8gICAgIHJldHVybiByZXN1bHRcbi8vICAgfVxuLy9cbi8vICAgdGhyb3R0bGVkLmNhbmNlbCA9IGZ1bmN0aW9uKCkge1xuLy8gICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KVxuLy8gICAgIHByZXZpb3VzID0gMFxuLy8gICAgIHRpbWVvdXQgPSB0aGlzQXJnID0gYXJncyA9IG51bGxcbi8vICAgfVxuLy9cbi8vICAgcmV0dXJuIHRocm90dGxlZFxuLy8gfVxuIl0sIm5hbWVzIjpbImNvbnN0IiwibGV0Il0sIm1hcHBpbmdzIjoiQUFBQUEsR0FBSyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDO0FBQ2xDQSxHQUFLLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUM7QUFDaENBLEdBQUssQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQztBQUNwQ0EsR0FBSyxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsbUJBQW1CLENBQUM7QUFDOUNBLEdBQUssQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTBEdEMsTUFBTSxDQUFDLE9BQU8sR0FBRyxTQUFTLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRTtFQUN0REMsR0FBRyxDQUFDLE9BQU8sR0FBRyxJQUFJO0VBQ2xCQSxHQUFHLENBQUMsUUFBUSxHQUFHLElBQUk7O0VBRW5CLElBQUksT0FBTyxJQUFJLEtBQUssVUFBVSxFQUFFO0lBQzlCLElBQUksR0FBRyxJQUFJOztHQUVaO0VBQ0QsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUU7SUFDbEIsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsU0FBUyxDQUFDO1FBQzlCLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO1FBQzFCLE9BQU87O0lBRVgsUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDO1FBQ2hDLFNBQVMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO1FBQzNCLFFBQVE7R0FDYjs7RUFFRCxPQUFPLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFO0lBQzFCLFNBQVMsRUFBRSxPQUFPO0lBQ2xCLFNBQVMsRUFBRSxJQUFJO0lBQ2YsVUFBVSxFQUFFLFFBQVE7R0FDckIsQ0FBQztDQUNIOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==