const now = Date . now ; export function debounce ( func , wait = 300 ) { let lastArgs ; let lastThis ; let maxWait ; let result ; let timerId ; let lastCallTime ; let lastInvokeTime = 0 ; const leading = false ; const maxing = false ; const trailing = true ; if ( typeof func !== 'function' ) { throw new TypeError ( 'Expected a function' ) ; } function invokeFunc ( time ) { const args = lastArgs ; const thisArg = lastThis ; lastArgs = lastThis = undefined ; lastInvokeTime = time ; result = func . apply ( thisArg , args ) ; return result ; } function shouldInvoke ( time ) { const timeSinceLastCall = time - lastCallTime ; const timeSinceLastInvoke = time - lastInvokeTime ; return ( lastCallTime === undefined || ( timeSinceLastCall >= wait ) || ( timeSinceLastCall < 0 ) || ( maxing && timeSinceLastInvoke >= maxWait ) ) ; } function remainingWait ( time ) { const timeSinceLastCall = time - lastCallTime ; const timeSinceLastInvoke = time - lastInvokeTime ; const timeWaiting = wait - timeSinceLastCall ; return maxing ? Math . min ( timeWaiting , maxWait - timeSinceLastInvoke ) : timeWaiting ; } function trailingEdge ( time ) { timerId = undefined ; if ( trailing && lastArgs ) { return invokeFunc ( time ) ; } lastArgs = lastThis = undefined ; return result ; } function timerExpired ( ) { const time = now ( ) ; if ( shouldInvoke ( time ) ) { return trailingEdge ( time ) ; } timerId = setTimeout ( timerExpired , remainingWait ( time ) ) ; } function leadingEdge ( time ) { lastInvokeTime = time ; timerId = setTimeout ( timerExpired , wait ) ; return leading ? invokeFunc ( time ) : result ; } function cancel ( ) { if ( timerId !== undefined ) { clearTimeout ( timerId ) ; } lastInvokeTime = 0 ; lastArgs = lastCallTime = lastThis = timerId = undefined ; } function flush ( ) { return timerId === undefined ? result : trailingEdge ( now ( ) ) ; } function debounced ( ) { const time = now ( ) ; const isInvoking = shouldInvoke ( time ) ; lastArgs = arguments ; lastThis = this ; lastCallTime = time ; if ( isInvoking ) { if ( timerId === undefined ) { return leadingEdge ( lastCallTime ) ; } if ( maxing ) { clearTimeout ( timerId ) ; timerId = setTimeout ( timerExpired , wait ) ; return invokeFunc ( lastCallTime ) ; } } if ( timerId === undefined ) { timerId = setTimeout ( timerExpired , wait ) ; } return result ; } debounced . cancel = cancel ; debounced . flush = flush ; return debounced ; }