From 6fe322da2781705156bf3ca07fb58f1610af2825 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 4 Apr 2013 08:52:42 -0700 Subject: [PATCH] Add an `options` object argument to `_.debounce` and `_.throttle`. [closes #222] Former-commit-id: d5eb3bc21d4a5c6d25314153f98d43a3d11eb4fa --- build/pre-compile.js | 2 ++ lodash.js | 69 ++++++++++++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/build/pre-compile.js b/build/pre-compile.js index 0e6b62360..4b4d8e3bc 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -156,6 +156,7 @@ 'keys', 'last', 'lastIndexOf', + 'leading', 'map', 'max', 'memoize', @@ -204,6 +205,7 @@ 'throttle', 'times', 'toArray', + 'trailing', 'unescape', 'unindexedChars', 'union', diff --git a/lodash.js b/lodash.js index 4775704ab..c6039eb93 100644 --- a/lodash.js +++ b/lodash.js @@ -4440,44 +4440,53 @@ /** * Creates a function that will delay the execution of `func` until after * `wait` milliseconds have elapsed since the last time it was invoked. Pass - * `true` for `immediate` to cause debounce to invoke `func` on the leading, - * instead of the trailing, edge of the `wait` timeout. Subsequent calls to - * the debounced function will return the result of the last `func` call. + * an `options` object to indicate that `func` should be invoked on the leading + * and/or trailing edge of the `wait` timeout. Subsequent calls to the debounced + * function will return the result of the last `func` call. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to debounce. * @param {Number} wait The number of milliseconds to delay. - * @param {Boolean} immediate A flag to indicate execution is on the leading - * edge of the timeout. + * @param {Object} options The options object. + * [leading=false] A boolean to specify execution on the leading edge of the timeout. + * [trailing=true] A boolean to specify execution on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * var lazyLayout = _.debounce(calculateLayout, 300); * jQuery(window).on('resize', lazyLayout); */ - function debounce(func, wait, immediate) { + function debounce(func, wait, options) { var args, result, thisArg, - timeoutId; + timeoutId, + trailing = true; function delayed() { timeoutId = null; - if (!immediate) { + if (trailing) { result = func.apply(thisArg, args); } } + if (options === true) { + var leading = true; + trailing = false; + } else if (options) { + leading = options.leading; + trailing = options.trailing; + } return function() { - var isImmediate = immediate && !timeoutId; + var isLeading = leading && !timeoutId; args = arguments; thisArg = this; clearTimeout(timeoutId); timeoutId = setTimeout(delayed, wait); - if (isImmediate) { + if (isLeading) { result = func.apply(thisArg, args); } return result; @@ -4647,39 +4656,57 @@ } /** - * Creates a function that, when executed, will only call the `func` - * function at most once per every `wait` milliseconds. If the throttled - * function is invoked more than once during the `wait` timeout, `func` will - * also be called on the trailing edge of the timeout. Subsequent calls to the - * throttled function will return the result of the last `func` call. + * Creates a function that, when executed, will only call the `func` function + * at most once per every `wait` milliseconds. If the throttled function is + * invoked more than once during the `wait` timeout, `func` will also be called + * on the trailing edge of the timeout. Pass an `options` object to indicate + * that `func` should be invoked on the leading and/or trailing edge of the + * `wait` timeout. Subsequent calls to the throttled function will return + * the result of the last `func` call. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to throttle. * @param {Number} wait The number of milliseconds to throttle executions to. + * @param {Object} options The options object. + * [leading=true] A boolean to specify execution on the leading edge of the timeout. + * [trailing=true] A boolean to specify execution on the trailing edge of the timeout. * @returns {Function} Returns the new throttled function. * @example * * var throttled = _.throttle(updatePosition, 100); * jQuery(window).on('scroll', throttled); */ - function throttle(func, wait) { + function throttle(func, wait, options) { var args, result, thisArg, timeoutId, - lastCalled = 0; + lastCalled = 0, + leading = true, + trailing = true; function trailingCall() { lastCalled = new Date; timeoutId = null; - result = func.apply(thisArg, args); + + if (trailing) { + result = func.apply(thisArg, args); + } + } + if (options === false) { + leading = false; + } else if (options) { + leading = options.leading; + trailing = options.trailing; } return function() { - var now = new Date, - remaining = wait - (now - lastCalled); - + var now = new Date; + if (!timeoutId && !leading) { + lastCalled = now; + } + var remaining = wait - (now - lastCalled); args = arguments; thisArg = this;