index.js 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /**
  2. * 返回一个自带消抖效果的函数,下文用fnDebounced表示。
  3. *
  4. * fn: 需要被消抖的函数
  5. * delay: 消抖时长
  6. * isImmediateCall: 是否在一组操作中的第一次调用时立即执行fn
  7. * isRememberLastCall:是否在一组中最后一次调用后等delay时长再执行fn
  8. *
  9. * 如果isRememberLastCall为false,意味着fn不会被延迟执行,所以fnDebounced执行时,要么在内部调用fn,同步返回fn返回值;要么内部决定本次不调用fn,同步返回null。
  10. * 如果isRememberLastCall为true,意味着fn可能被延迟执行,所以fnDebounced会返回一个Promise,在fn被调用时用其返回值resolve该Promise,或者在fn的延时调用计划被取消时用'canceled'resolve该Promise。(不宜reject,否则又没有人去catch,会导致浏览器报错。)
  11. */
  12. export function debounce(fn, delay = 250, isImmediateCall = false, isRememberLastCall = true) {
  13. console.assert(isImmediateCall || isRememberLastCall, 'isImmediateCall 和 isRememberLastCall 至少应有一个是true,否则没有意义!')
  14. let timer = null
  15. let retPromiseLastTimeResolver = null
  16. // 上次调用的时刻
  17. let lastCallTime = 0
  18. if (isImmediateCall && !isRememberLastCall) {
  19. return function (...args) {
  20. let ret = null
  21. const currentTime = Date.now()
  22. if (currentTime - lastCallTime >= delay) {
  23. ret = fn.apply(this, args)
  24. }
  25. lastCallTime = currentTime
  26. return ret
  27. }
  28. } else if (!isImmediateCall && isRememberLastCall) {
  29. return function (...args) {
  30. if (timer) {
  31. clearTimeout(timer)
  32. timer = null
  33. }
  34. if (retPromiseLastTimeResolver) {
  35. retPromiseLastTimeResolver('canceled')
  36. retPromiseLastTimeResolver = null
  37. }
  38. const ret = new Promise((resolve, reject) => {
  39. retPromiseLastTimeResolver = resolve
  40. timer = setTimeout(() => {
  41. timer = null
  42. retPromiseLastTimeResolver = null
  43. resolve(fn.apply(this, args))
  44. }, delay)
  45. })
  46. return ret
  47. }
  48. } else if (isImmediateCall && isRememberLastCall) {
  49. return function (...args) {
  50. const currentTime = Date.now()
  51. if (currentTime - lastCallTime >= delay) { // 一组操作中的第一次
  52. const res = fn.apply(this, args)
  53. lastCallTime = currentTime
  54. return Promise.resolve(res)
  55. } else { // 一组中的后续调用
  56. if (timer) { // 在此之前存在中间调用
  57. lastCallTime = currentTime
  58. clearTimeout(timer)
  59. timer = null
  60. }
  61. if (retPromiseLastTimeResolver) {
  62. retPromiseLastTimeResolver('canceled')
  63. retPromiseLastTimeResolver = null
  64. }
  65. const ret = new Promise((resolve, reject) => {
  66. retPromiseLastTimeResolver = resolve
  67. timer = setTimeout(() => {
  68. lastCallTime = 0
  69. timer = null
  70. retPromiseLastTimeResolver = null
  71. resolve(fn.apply(this, args))
  72. }, delay)
  73. })
  74. return ret
  75. }
  76. }
  77. } else {
  78. console.error('不应该执行到这里!')
  79. }
  80. }
  81. export default {
  82. debounce,
  83. }