12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- /**
- * 返回一个自带消抖效果的函数,下文用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的延时调用计划被取消时用'canceled'resolve该Promise。(不宜reject,否则又没有人去catch,会导致浏览器报错。)
- */
- export function debounce(fn, delay = 250, isImmediateCall = false, isRememberLastCall = true) {
- console.assert(isImmediateCall || isRememberLastCall, 'isImmediateCall 和 isRememberLastCall 至少应有一个是true,否则没有意义!')
- let timer = null
- let retPromiseLastTimeResolver = 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 (retPromiseLastTimeResolver) {
- retPromiseLastTimeResolver('canceled')
- retPromiseLastTimeResolver = null
- }
- const ret = new Promise((resolve, reject) => {
- retPromiseLastTimeResolver = resolve
- timer = setTimeout(() => {
- timer = null
- retPromiseLastTimeResolver = 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 (retPromiseLastTimeResolver) {
- retPromiseLastTimeResolver('canceled')
- retPromiseLastTimeResolver = null
- }
- const ret = new Promise((resolve, reject) => {
- retPromiseLastTimeResolver = resolve
- timer = setTimeout(() => {
- lastCallTime = 0
- timer = null
- retPromiseLastTimeResolver = null
- resolve(fn.apply(this, args))
- }, delay)
- })
- return ret
- }
- }
- } else {
- console.error('不应该执行到这里!')
- }
- }
- export default {
- debounce,
- }
|