index.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. function debounce(function_, wait = 100, options = {}) {
  2. if (typeof function_ !== 'function') {
  3. throw new TypeError(`Expected the first parameter to be a function, got \`${typeof function_}\`.`);
  4. }
  5. if (wait < 0) {
  6. throw new RangeError('`wait` must not be negative.');
  7. }
  8. // TODO: Deprecate the boolean parameter at some point.
  9. const {immediate} = typeof options === 'boolean' ? {immediate: options} : options;
  10. let storedContext;
  11. let storedArguments;
  12. let timeoutId;
  13. let timestamp;
  14. let result;
  15. function later() {
  16. const last = Date.now() - timestamp;
  17. if (last < wait && last >= 0) {
  18. timeoutId = setTimeout(later, wait - last);
  19. } else {
  20. timeoutId = undefined;
  21. if (!immediate) {
  22. const callContext = storedContext;
  23. const callArguments = storedArguments;
  24. storedContext = undefined;
  25. storedArguments = undefined;
  26. result = function_.apply(callContext, callArguments);
  27. }
  28. }
  29. }
  30. const debounced = function (...arguments_) {
  31. if (storedContext && this !== storedContext) {
  32. throw new Error('Debounced method called with different contexts.');
  33. }
  34. storedContext = this; // eslint-disable-line unicorn/no-this-assignment
  35. storedArguments = arguments_;
  36. timestamp = Date.now();
  37. const callNow = immediate && !timeoutId;
  38. if (!timeoutId) {
  39. timeoutId = setTimeout(later, wait);
  40. }
  41. if (callNow) {
  42. const callContext = storedContext;
  43. const callArguments = storedArguments;
  44. storedContext = undefined;
  45. storedArguments = undefined;
  46. result = function_.apply(callContext, callArguments);
  47. }
  48. return result;
  49. };
  50. debounced.clear = () => {
  51. if (!timeoutId) {
  52. return;
  53. }
  54. clearTimeout(timeoutId);
  55. timeoutId = undefined;
  56. };
  57. debounced.flush = () => {
  58. if (!timeoutId) {
  59. return;
  60. }
  61. const callContext = storedContext;
  62. const callArguments = storedArguments;
  63. storedContext = undefined;
  64. storedArguments = undefined;
  65. result = function_.apply(callContext, callArguments);
  66. clearTimeout(timeoutId);
  67. timeoutId = undefined;
  68. };
  69. return debounced;
  70. }
  71. // Adds compatibility for ES modules
  72. module.exports.debounce = debounce;
  73. module.exports = debounce;