作者:奥兰度

    1. // 一个用来一定时间之后,最后执行传入的函数,
    2. // 用来控制一定时间段内,只触发一次传入的函数
    3. // 防抖
    4. function debounce(fn, time) {
    5. let timer
    6. return function (...args) {
    7. if (timer) {
    8. clearTimeout(timer)
    9. }
    10. timer = setTimeout(() => {
    11. fn(...args)
    12. }, time)
    13. }
    14. }
    15. // 节流
    16. function throttle(fn, time) {
    17. let timer
    18. return function (...args) {
    19. if (timer) {
    20. return
    21. }
    22. timer = setTimeout(() => {
    23. fn(...args)
    24. timer = null
    25. }, time)
    26. }
    27. }

    作者:xl

    1. function debounce(func, wait) {
    2. let timeout;
    3. return function() {
    4. const context = this;
    5. const args = arguments;
    6. clearTimeout(timeout);
    7. timeout = setTimeout(function() {
    8. func.apply(context, args);
    9. }, wait);
    10. }
    11. }
    12. function throttle(fn, delay) {
    13. let cur = Date.now();
    14. return function() {
    15. const context = this;
    16. const args = arguments;
    17. const now = Date.now();
    18. if (now - cur >= delay) {
    19. cur = Date.now();
    20. fn.apply(context, args);
    21. }
    22. }
    23. }

    作者:安静

    1. function throttle(fn, delay) {
    2. let timer = null;
    3. return function () {
    4. if (timer) {
    5. return;
    6. }
    7. timer = setTimeout(() => {
    8. fn.apply(this, arguments);
    9. timer = null;
    10. }, delay);
    11. };
    12. }
    13. function debounce(fn, delay) {
    14. // 定时器
    15. let timer = null;
    16. // 将debounce处理结果当作函数返回
    17. return function () {
    18. // 每次事件被触发时,都去清除之前的旧定时器
    19. if (timer) {
    20. clearTimeout(timer);
    21. }
    22. // 设立新定时器
    23. timer = setTimeout(() => {
    24. fn.apply(this, arguments);
    25. }, delay);
    26. };
    27. }

    作者:gochri

    1. let myDebounce = (func, wait = 0, immediately = true, option = { leading: false, maxWait: 0, trailing: true }) => {
    2. if (typeof func !== 'function') {
    3. throw new Error('Expected a function')
    4. }
    5. if (typeof wait !== 'number') {
    6. throw new Error('wait not a number')
    7. }
    8. let timeoutID = null
    9. function debounced(...args) {
    10. if (timeoutID !== null) {
    11. clearTimeout(timeoutID);
    12. }
    13. timeoutID = setTimeout(func, wait);
    14. }
    15. return debounced
    16. }
    17. // 测试用例
    18. let foo = () => { console.log('foo') }
    19. // foo()
    20. let debounced = myDebounce(foo, 100)
    21. // debounced()
    22. for (let i = 0; i < 10; i++) {
    23. // setTimeout(() => {
    24. debounced()
    25. // }, 300);
    26. }
    27. // foo
    28. // 测试用例结束
    29. // TODO
    30. import Debounce from 'lodash-decorators/debounce';
    31. @debounce(500)
    32. function name(params) {
    33. }

    作者:lodash

    1. import isObject from './isObject.js'
    2. import root from './.internal/root.js'
    3. /**
    4. * Creates a debounced function that delays invoking `func` until after `wait`
    5. * milliseconds have elapsed since the last time the debounced function was
    6. * invoked, or until the next browser frame is drawn. The debounced function
    7. * comes with a `cancel` method to cancel delayed `func` invocations and a
    8. * `flush` method to immediately invoke them. Provide `options` to indicate
    9. * whether `func` should be invoked on the leading and/or trailing edge of the
    10. * `wait` timeout. The `func` is invoked with the last arguments provided to the
    11. * debounced function. Subsequent calls to the debounced function return the
    12. * result of the last `func` invocation.
    13. *
    14. * **Note:** If `leading` and `trailing` options are `true`, `func` is
    15. * invoked on the trailing edge of the timeout only if the debounced function
    16. * is invoked more than once during the `wait` timeout.
    17. *
    18. * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
    19. * until the next tick, similar to `setTimeout` with a timeout of `0`.
    20. *
    21. * If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
    22. * invocation will be deferred until the next frame is drawn (typically about
    23. * 16ms).
    24. *
    25. * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
    26. * for details over the differences between `debounce` and `throttle`.
    27. *
    28. * @since 0.1.0
    29. * @category Function
    30. * @param {Function} func The function to debounce.
    31. * @param {number} [wait=0]
    32. * The number of milliseconds to delay; if omitted, `requestAnimationFrame` is
    33. * used (if available).
    34. * @param {Object} [options={}] The options object.
    35. * @param {boolean} [options.leading=false]
    36. * Specify invoking on the leading edge of the timeout.
    37. * @param {number} [options.maxWait]
    38. * The maximum time `func` is allowed to be delayed before it's invoked.
    39. * @param {boolean} [options.trailing=true]
    40. * Specify invoking on the trailing edge of the timeout.
    41. * @returns {Function} Returns the new debounced function.
    42. * @example
    43. *
    44. * // Avoid costly calculations while the window size is in flux.
    45. * jQuery(window).on('resize', debounce(calculateLayout, 150))
    46. *
    47. * // Invoke `sendMail` when clicked, debouncing subsequent calls.
    48. * jQuery(element).on('click', debounce(sendMail, 300, {
    49. * 'leading': true,
    50. * 'trailing': false
    51. * }))
    52. *
    53. * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
    54. * const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })
    55. * const source = new EventSource('/stream')
    56. * jQuery(source).on('message', debounced)
    57. *
    58. * // Cancel the trailing debounced invocation.
    59. * jQuery(window).on('popstate', debounced.cancel)
    60. *
    61. * // Check for pending invocations.
    62. * const status = debounced.pending() ? "Pending..." : "Ready"
    63. */
    64. function debounce(func, wait, options) {
    65. let lastArgs,
    66. lastThis,
    67. maxWait,
    68. result,
    69. timerId,
    70. lastCallTime
    71. let lastInvokeTime = 0
    72. let leading = false
    73. let maxing = false
    74. let trailing = true
    75. // Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
    76. const useRAF = (!wait && wait !== 0 && typeof root.requestAnimationFrame === 'function')
    77. if (typeof func !== 'function') {
    78. throw new TypeError('Expected a function')
    79. }
    80. wait = +wait || 0
    81. if (isObject(options)) {
    82. leading = !!options.leading
    83. maxing = 'maxWait' in options
    84. maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait
    85. trailing = 'trailing' in options ? !!options.trailing : trailing
    86. }
    87. function invokeFunc(time) {
    88. const args = lastArgs
    89. const thisArg = lastThis
    90. lastArgs = lastThis = undefined
    91. lastInvokeTime = time
    92. result = func.apply(thisArg, args)
    93. return result
    94. }
    95. function startTimer(pendingFunc, wait) {
    96. if (useRAF) {
    97. root.cancelAnimationFrame(timerId)
    98. return root.requestAnimationFrame(pendingFunc)
    99. }
    100. return setTimeout(pendingFunc, wait)
    101. }
    102. function cancelTimer(id) {
    103. if (useRAF) {
    104. return root.cancelAnimationFrame(id)
    105. }
    106. clearTimeout(id)
    107. }
    108. function leadingEdge(time) {
    109. // Reset any `maxWait` timer.
    110. lastInvokeTime = time
    111. // Start the timer for the trailing edge.
    112. timerId = startTimer(timerExpired, wait)
    113. // Invoke the leading edge.
    114. return leading ? invokeFunc(time) : result
    115. }
    116. function remainingWait(time) {
    117. const timeSinceLastCall = time - lastCallTime
    118. const timeSinceLastInvoke = time - lastInvokeTime
    119. const timeWaiting = wait - timeSinceLastCall
    120. return maxing
    121. ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
    122. : timeWaiting
    123. }
    124. function shouldInvoke(time) {
    125. const timeSinceLastCall = time - lastCallTime
    126. const timeSinceLastInvoke = time - lastInvokeTime
    127. // Either this is the first call, activity has stopped and we're at the
    128. // trailing edge, the system time has gone backwards and we're treating
    129. // it as the trailing edge, or we've hit the `maxWait` limit.
    130. return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
    131. (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait))
    132. }
    133. function timerExpired() {
    134. const time = Date.now()
    135. if (shouldInvoke(time)) {
    136. return trailingEdge(time)
    137. }
    138. // Restart the timer.
    139. timerId = startTimer(timerExpired, remainingWait(time))
    140. }
    141. function trailingEdge(time) {
    142. timerId = undefined
    143. // Only invoke if we have `lastArgs` which means `func` has been
    144. // debounced at least once.
    145. if (trailing && lastArgs) {
    146. return invokeFunc(time)
    147. }
    148. lastArgs = lastThis = undefined
    149. return result
    150. }
    151. function cancel() {
    152. if (timerId !== undefined) {
    153. cancelTimer(timerId)
    154. }
    155. lastInvokeTime = 0
    156. lastArgs = lastCallTime = lastThis = timerId = undefined
    157. }
    158. function flush() {
    159. return timerId === undefined ? result : trailingEdge(Date.now())
    160. }
    161. function pending() {
    162. return timerId !== undefined
    163. }
    164. function debounced(...args) {
    165. const time = Date.now()
    166. const isInvoking = shouldInvoke(time)
    167. lastArgs = args
    168. lastThis = this
    169. lastCallTime = time
    170. if (isInvoking) {
    171. if (timerId === undefined) {
    172. return leadingEdge(lastCallTime)
    173. }
    174. if (maxing) {
    175. // Handle invocations in a tight loop.
    176. timerId = startTimer(timerExpired, wait)
    177. return invokeFunc(lastCallTime)
    178. }
    179. }
    180. if (timerId === undefined) {
    181. timerId = startTimer(timerExpired, wait)
    182. }
    183. return result
    184. }
    185. debounced.cancel = cancel
    186. debounced.flush = flush
    187. debounced.pending = pending
    188. return debounced
    189. }
    190. export default debounce
    191. let fn = debounce(console.log).bind(this)
    192. for(let i = 0; i < 10000; i++) {
    193. fn(i)
    194. }

    作者:lodash.throttle

    1. import debounce from './debounce.js'
    2. import isObject from './isObject.js'
    3. /**
    4. * Creates a throttled function that only invokes `func` at most once per
    5. * every `wait` milliseconds (or once per browser frame). The throttled function
    6. * comes with a `cancel` method to cancel delayed `func` invocations and a
    7. * `flush` method to immediately invoke them. Provide `options` to indicate
    8. * whether `func` should be invoked on the leading and/or trailing edge of the
    9. * `wait` timeout. The `func` is invoked with the last arguments provided to the
    10. * throttled function. Subsequent calls to the throttled function return the
    11. * result of the last `func` invocation.
    12. *
    13. * **Note:** If `leading` and `trailing` options are `true`, `func` is
    14. * invoked on the trailing edge of the timeout only if the throttled function
    15. * is invoked more than once during the `wait` timeout.
    16. *
    17. * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
    18. * until the next tick, similar to `setTimeout` with a timeout of `0`.
    19. *
    20. * If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
    21. * invocation will be deferred until the next frame is drawn (typically about
    22. * 16ms).
    23. *
    24. * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
    25. * for details over the differences between `throttle` and `debounce`.
    26. *
    27. * @since 0.1.0
    28. * @category Function
    29. * @param {Function} func The function to throttle.
    30. * @param {number} [wait=0]
    31. * The number of milliseconds to throttle invocations to; if omitted,
    32. * `requestAnimationFrame` is used (if available).
    33. * @param {Object} [options={}] The options object.
    34. * @param {boolean} [options.leading=true]
    35. * Specify invoking on the leading edge of the timeout.
    36. * @param {boolean} [options.trailing=true]
    37. * Specify invoking on the trailing edge of the timeout.
    38. * @returns {Function} Returns the new throttled function.
    39. * @example
    40. *
    41. * // Avoid excessively updating the position while scrolling.
    42. * jQuery(window).on('scroll', throttle(updatePosition, 100))
    43. *
    44. * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
    45. * const throttled = throttle(renewToken, 300000, { 'trailing': false })
    46. * jQuery(element).on('click', throttled)
    47. *
    48. * // Cancel the trailing throttled invocation.
    49. * jQuery(window).on('popstate', throttled.cancel)
    50. */
    51. function throttle(func, wait, options) {
    52. let leading = true
    53. let trailing = true
    54. if (typeof func !== 'function') {
    55. throw new TypeError('Expected a function')
    56. }
    57. if (isObject(options)) {
    58. leading = 'leading' in options ? !!options.leading : leading
    59. trailing = 'trailing' in options ? !!options.trailing : trailing
    60. }
    61. return debounce(func, wait, {
    62. leading,
    63. trailing,
    64. 'maxWait': wait
    65. })
    66. }
    67. export default throttle