|
@@ -0,0 +1,85 @@
|
|
|
+/**
|
|
|
+ * 返回一个自带消抖效果的函数,下文用fnDebounced表示。
|
|
|
+ *
|
|
|
+ * fn: 需要被消抖的函数
|
|
|
+ * delay: 消抖时长
|
|
|
+ * isImmediateCall: 是否在一组操作中的第一次调用时立即执行fn
|
|
|
+ * isRememberLastCall:是否在一组中最后一次调用后等delay时长再执行fn
|
|
|
+ *
|
|
|
+ * 如果isRememberLastCall为false,意味着fn不会被延迟执行,所以fnDebounced执行时,要么在内部调用fn,同步返回fn返回值;要么内部决定本次不调用fn,同步返回null。
|
|
|
+ * 如果isRememberLastCall为true,意味着fn可能被延迟执行,所以fnDebounced会返回一个Promise,在fn被调用时用其返回值resolve该Promise,或者在fn的延时调用计划被取消时用null reject该Promise。
|
|
|
+ */
|
|
|
+export function debounce(fn, delay = 250, isImmediateCall = false, isRememberLastCall = true) {
|
|
|
+ console.assert(isImmediateCall || isRememberLastCall, 'isImmediateCall 和 isRememberLastCall 至少应有一个是true,否则没有意义!')
|
|
|
+ let timer = null
|
|
|
+ let retPromiseLastTimeRejector = null
|
|
|
+ // 上次调用的时刻
|
|
|
+ let lastCallTime = 0
|
|
|
+
|
|
|
+ if (isImmediateCall && !isRememberLastCall) {
|
|
|
+ return function (...args) {
|
|
|
+ let ret = null
|
|
|
+ const currentTime = Date.now()
|
|
|
+ if (currentTime - lastCallTime >= delay) {
|
|
|
+ ret = fn.apply(this, args)
|
|
|
+ }
|
|
|
+ lastCallTime = currentTime
|
|
|
+ return ret
|
|
|
+ }
|
|
|
+ } else if (!isImmediateCall && isRememberLastCall) {
|
|
|
+ return function (...args) {
|
|
|
+ if (timer) {
|
|
|
+ clearTimeout(timer)
|
|
|
+ timer = null
|
|
|
+ }
|
|
|
+ if (retPromiseLastTimeRejector) {
|
|
|
+ retPromiseLastTimeRejector(null)
|
|
|
+ retPromiseLastTimeRejector = null
|
|
|
+ }
|
|
|
+ const ret = new Promise((resolve, reject) => {
|
|
|
+ retPromiseLastTimeRejector = reject
|
|
|
+ timer = setTimeout(() => {
|
|
|
+ timer = null
|
|
|
+ retPromiseLastTimeRejector = null
|
|
|
+ resolve(fn.apply(this, args))
|
|
|
+ }, delay)
|
|
|
+ })
|
|
|
+ return ret
|
|
|
+ }
|
|
|
+ } else if (isImmediateCall && isRememberLastCall) {
|
|
|
+ return function (...args) {
|
|
|
+ const currentTime = Date.now()
|
|
|
+ if (currentTime - lastCallTime >= delay) { // 一组操作中的第一次
|
|
|
+ const res = fn.apply(this, args)
|
|
|
+ lastCallTime = currentTime
|
|
|
+ return Promise.resolve(res)
|
|
|
+ } else { // 一组中的后续调用
|
|
|
+ if (timer) { // 在此之前存在中间调用
|
|
|
+ lastCallTime = currentTime
|
|
|
+ clearTimeout(timer)
|
|
|
+ timer = null
|
|
|
+ }
|
|
|
+ if (retPromiseLastTimeRejector) {
|
|
|
+ retPromiseLastTimeRejector(null)
|
|
|
+ retPromiseLastTimeRejector = null
|
|
|
+ }
|
|
|
+ const ret = new Promise((resolve, reject) => {
|
|
|
+ retPromiseLastTimeRejector = reject
|
|
|
+ timer = setTimeout(() => {
|
|
|
+ lastCallTime = 0
|
|
|
+ timer = null
|
|
|
+ retPromiseLastTimeRejector = null
|
|
|
+ resolve(fn.apply(this, args))
|
|
|
+ }, delay)
|
|
|
+ })
|
|
|
+ return ret
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.error('不应该执行到这里!')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default {
|
|
|
+ debounce,
|
|
|
+}
|