throttle.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /**
  2. * @desc 函数节流
  3. * 适用于限制`resize`和`scroll`等函数的调用频率
  4. *
  5. * @param {Number} delay 0 或者更大的毫秒数。 对于事件回调,大约100或250毫秒(或更高)的延迟是最有用的。
  6. * @param {Boolean} noTrailing 可选,默认为false。
  7. * 如果noTrailing为true,当节流函数被调用,每过`delay`毫秒`callback`也将执行一次。
  8. * 如果noTrailing为false或者未传入,`callback`将在最后一次调用节流函数后再执行一次.
  9. * (延迟`delay`毫秒之后,节流函数没有被调用,内部计数器会复位)
  10. * @param {Function} callback 延迟毫秒后执行的函数。`this`上下文和所有参数都是按原样传递的,
  11. * 执行去节流功能时,调用`callback`。
  12. * @param {Boolean} debounceMode 如果`debounceMode`为true,`clear`在`delay`ms后执行。
  13. * 如果debounceMode是false,`callback`在`delay` ms之后执行。
  14. *
  15. * @return {Function} 新的节流函数
  16. */
  17. module.exports = function throttle(delay, noTrailing, callback, debounceMode) {
  18. // After wrapper has stopped being called, this timeout ensures that
  19. // `callback` is executed at the proper times in `throttle` and `end`
  20. // debounce modes.
  21. var timeoutID;
  22. // Keep track of the last time `callback` was executed.
  23. var lastExec = 0;
  24. // `noTrailing` defaults to falsy.
  25. if (typeof noTrailing !== 'boolean') {
  26. debounceMode = callback;
  27. callback = noTrailing;
  28. noTrailing = undefined;
  29. };
  30. // The `wrapper` function encapsulates all of the throttling / debouncing
  31. // functionality and when executed will limit the rate at which `callback`
  32. // is executed.
  33. function wrapper() {
  34. var self = this;
  35. var elapsed = Number(new Date()) - lastExec;
  36. var args = arguments;
  37. // Execute `callback` and update the `lastExec` timestamp.
  38. function exec() {
  39. lastExec = Number(new Date());
  40. callback.apply(self, args);
  41. };
  42. // If `debounceMode` is true (at begin) this is used to clear the flag
  43. // to allow future `callback` executions.
  44. function clear() {
  45. timeoutID = undefined;
  46. };
  47. if (debounceMode && !timeoutID) {
  48. // Since `wrapper` is being called for the first time and
  49. // `debounceMode` is true (at begin), execute `callback`.
  50. exec();
  51. };
  52. // Clear any existing timeout.
  53. if (timeoutID) {
  54. clearTimeout(timeoutID);
  55. };
  56. if (debounceMode === undefined && elapsed > delay) {
  57. // In throttle mode, if `delay` time has been exceeded, execute
  58. // `callback`.
  59. exec();
  60. } else if (noTrailing !== true) {
  61. // In trailing throttle mode, since `delay` time has not been
  62. // exceeded, schedule `callback` to execute `delay` ms after most
  63. // recent execution.
  64. //
  65. // If `debounceMode` is true (at begin), schedule `clear` to execute
  66. // after `delay` ms.
  67. //
  68. // If `debounceMode` is false (at end), schedule `callback` to
  69. // execute after `delay` ms.
  70. timeoutID = setTimeout(debounceMode ? clear : exec, debounceMode === undefined ? delay - elapsed : delay);
  71. };
  72. };
  73. // Return the wrapper function.
  74. return wrapper;
  75. };