js - 防抖和节流
debounce
创建一个防抖函数。
参数
fn
: Function - 需要防抖的函数delay
: number - 延迟时间,单位毫秒,默认300immediate
: boolean - 是否立即执行,默认false
返回值
Function
- 防抖后的函数,包含cancel方法用于取消防抖
使用示例
javascript
// 基础用法
const debouncedFn = debounce(() => console.log('触发'), 300);
window.addEventListener('resize', debouncedFn);
// 取消防抖
debouncedFn.cancel();
throttle
创建一个节流函数。
参数
fn
: Function - 需要节流的函数interval
: number - 间隔时间,单位毫秒,默认300options
: Object - 配置选项leading
: boolean - 是否第一次立即执行,默认truetrailing
: boolean - 是否最后一次执行,默认true
返回值
Function
- 节流后的函数,包含cancel方法用于取消节流
使用示例
javascript
// 基础用法
const throttledScroll = throttle(() => console.log('滚动'), 300);
window.addEventListener('scroll', throttledScroll);
// 自定义首尾是否执行
const throttledMove = throttle(
() => console.log('移动'),
300,
{ leading: false, trailing: true }
);
源码
js
/**
* 防抖函数 - 在最后一次触发后延迟执行
* @param {Function} fn - 需要防抖的函数
* @param {number} delay - 延迟时间,单位毫秒
* @param {boolean} immediate - 是否立即执行
* @returns {Function} 防抖后的函数
*
* @example
* // 基础用法
* const debouncedFn = debounce(() => console.log('触发'), 300)
* window.addEventListener('resize', debouncedFn)
*
* // 立即执行
* const debouncedClick = debounce(
* () => console.log('点击'),
* 300,
* true
* )
* button.addEventListener('click', debouncedClick)
*
* // 取消防抖
* debouncedClick.cancel()
*/
function debounce(fn, delay = 300, immediate = false) {
let timer = null
let isInvoke = false
const _debounce = function (...args) {
if (timer) clearTimeout(timer)
// 第一次是否立即执行
if (immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
return
}
timer = setTimeout(() => {
fn.apply(this, args)
isInvoke = false
timer = null
}, delay)
}
// 取消功能
_debounce.cancel = function () {
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
js
/**
* 节流函数 - 按时间间隔执行
* @param {Function} fn - 需要节流的函数
* @param {number} interval - 间隔时间,单位毫秒
* @param {boolean} leading - 是否第一次立即执行
* @param {boolean} trailing - 是否最后一次执行
* @returns {Function} 节流后的函数
*
* @example
* // 基础用法
* const throttledScroll = throttle(
* () => console.log('滚动'),
* 300
* )
* window.addEventListener('scroll', throttledScroll)
*
* // 自定义首尾是否执行
* const throttledMove = throttle(
* () => console.log('移动'),
* 300,
* { leading: false, trailing: true }
* )
* element.addEventListener('mousemove', throttledMove)
*
* // 取消节流
* throttledMove.cancel()
*/
function throttle(fn, interval = 300, { leading = true, trailing = true } = {}) {
let startTime = 0
let timer = null
const _throttle = function (...args) {
const nowTime = Date.now()
// 第一次是否需要立即执行
if (!leading && startTime === 0) {
startTime = nowTime
}
const remainTime = interval - (nowTime - startTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
fn.apply(this, args)
startTime = nowTime
return
}
// 最后一次是否需要执行
if (trailing && !timer) {
timer = setTimeout(() => {
fn.apply(this, args)
startTime = Date.now()
timer = null
}, remainTime)
}
}
// 取消功能
_throttle.cancel = function () {
if (timer) clearTimeout(timer)
timer = null
startTime = 0
}
return _throttle
}