Debounce.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /* @see https://github.com/lodash/lodash/blob/master/debounce.js */
  2. /* @see https://www.lodashjs.com/docs/lodash.debounce */
  3. function debounce(func, wait, options) {
  4. var lastArgs,
  5. lastThis,
  6. maxWait,
  7. result,
  8. timerId,
  9. lastCallTime;
  10. var lastInvokeTime = 0;
  11. var leading = false;
  12. var maxing = false;
  13. var trailing = true;
  14. if (typeof func !== 'function') {
  15. throw new TypeError('Expected a function')
  16. }
  17. wait = +wait || 0;
  18. if (isObject(options)) {
  19. leading = !!options.leading;
  20. maxing = 'maxWait' in options;
  21. maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : wait;
  22. trailing = 'trailing' in options ? !!options.trailing : trailing
  23. }
  24. function isObject(value) {
  25. var type = typeof value;
  26. return value != null && (type === 'object' || type === 'function')
  27. }
  28. function invokeFunc(time) {
  29. var args = lastArgs;
  30. var thisArg = lastThis;
  31. lastArgs = lastThis = undefined;
  32. lastInvokeTime = time;
  33. result = func.apply(thisArg, args);
  34. return result
  35. }
  36. function startTimer(pendingFunc, wait) {
  37. return setTimeout(pendingFunc, wait)
  38. }
  39. function cancelTimer(id) {
  40. clearTimeout(id)
  41. }
  42. function leadingEdge(time) {
  43. // Reset any `maxWait` timer.
  44. lastInvokeTime = time;
  45. // Start the timer for the trailing edge.
  46. timerId = startTimer(timerExpired, wait);
  47. // Invoke the leading edge.
  48. return leading ? invokeFunc(time) : result
  49. }
  50. function remainingWait(time) {
  51. var timeSinceLastCall = time - lastCallTime;
  52. var timeSinceLastInvoke = time - lastInvokeTime;
  53. var timeWaiting = wait - timeSinceLastCall;
  54. return maxing
  55. ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
  56. : timeWaiting
  57. }
  58. function shouldInvoke(time) {
  59. var timeSinceLastCall = time - lastCallTime;
  60. var timeSinceLastInvoke = time - lastInvokeTime;
  61. // Either this is the first call, activity has stopped and we're at the
  62. // trailing edge, the system time has gone backwards and we're treating
  63. // it as the trailing edge, or we've hit the `maxWait` limit.
  64. return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
  65. (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait))
  66. }
  67. function timerExpired() {
  68. var time = Date.now();
  69. if (shouldInvoke(time)) {
  70. return trailingEdge(time)
  71. }
  72. // Restart the timer.
  73. timerId = startTimer(timerExpired, remainingWait(time))
  74. }
  75. function trailingEdge(time) {
  76. timerId = undefined;
  77. // Only invoke if we have `lastArgs` which means `func` has been
  78. // debounced at least once.
  79. if (trailing && lastArgs) {
  80. return invokeFunc(time)
  81. }
  82. lastArgs = lastThis = undefined;
  83. return result
  84. }
  85. function cancel() {
  86. if (timerId !== undefined) {
  87. cancelTimer(timerId)
  88. }
  89. lastInvokeTime = 0;
  90. lastArgs = lastCallTime = lastThis = timerId = undefined
  91. }
  92. function flush() {
  93. return timerId === undefined ? result : trailingEdge(Date.now())
  94. }
  95. function pending() {
  96. return timerId !== undefined
  97. }
  98. function debounced() {
  99. var time = Date.now();
  100. var isInvoking = shouldInvoke(time);
  101. lastArgs = arguments;
  102. lastThis = this;
  103. lastCallTime = time;
  104. if (isInvoking) {
  105. if (timerId === undefined) {
  106. return leadingEdge(lastCallTime)
  107. }
  108. if (maxing) {
  109. // Handle invocations in a tight loop.
  110. timerId = startTimer(timerExpired, wait);
  111. return invokeFunc(lastCallTime)
  112. }
  113. }
  114. if (timerId === undefined) {
  115. timerId = startTimer(timerExpired, wait)
  116. }
  117. return result
  118. }
  119. debounced.cancel = cancel;
  120. debounced.flush = flush;
  121. debounced.pending = pending;
  122. return debounced
  123. }
  124. export default debounce