src/utils/fn.js
/**
* Function module.
* @module base/utils/func
*/
/**
* Returns a function, that, as long as it continues to be invoked, will not
* be triggered. The function will be called after it stops being called for
* N milliseconds. If `immediate` is passed, trigger the function on the
* leading edge, instead of the trailing. The function also has a property 'clear'
* that is a function which will clear the timer to prevent previously scheduled executions.
*
* @source underscore.js
* @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
* @param {Function} func
* Function to wrap.
* @param {Number} wait
* Timeout in ms (`60`).
* @param {Boolean} immediate
* Whether to execute at the beginning (`false`).
*
* @returns {Function}
* A new function that wraps the `func` function passed in.
*/
export function debounce(func, wait = 60, immediate = false) {
var timeout, args, context, timestamp, result
function later() {
var last = Date.now() - timestamp
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
if (!immediate) {
result = func.apply(context, args)
context = args = null
}
}
}
var debounced = function() {
context = this
args = arguments
timestamp = Date.now()
var callNow = immediate && !timeout
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
debounced.clear = function() {
if (timeout) {
clearTimeout(timeout)
timeout = null
}
}
return debounced
}
/**
* Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.
*
* @param {Function} func
* Function to wrap.
* @param {Number} wait
* Number of milliseconds that must elapse between `func` invocations.
*
* @returns {Function}
* A new function that wraps the `func` function passed in.
*/
export function throttle(func, wait = 60) {
var ctx, args, rtn, timeoutID // caching
var last = 0
return function throttled() {
ctx = this
args = arguments
var delta = new Date() - last
if (!timeoutID)
if (delta >= wait) call()
else timeoutID = setTimeout(call, wait - delta)
return rtn
}
function call() {
timeoutID = 0
last = +new Date()
rtn = func.apply(ctx, args)
ctx = null
args = null
}
}
/**
* Returns undefined irrespective of the arguments passed to it.
*
* Using the noop the intent of a default callback is clear.
* An empty function might indicate unfinished business.
*
* @returns {undefined}
*/
export function noop() {}
/**
* Execute functionality just once.
*
* @param {Function} fn - Function to execute just once.
* @param {*} context - Context to execute the function in.
*
* @returns {Function}
*/
export function once(fn, context) {
var result
return function() {
if (fn) {
result = fn.apply(context || this, arguments)
fn = null
}
return result
}
}
export default {
debounce,
throttle,
noop,
once
}