小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
术语理解
防抖(debounce):防止抖动引起问题,核心在于抖动,间隔。一段时间内连续被触发,则只在最后一次执行。
节流(throttle):节约流量,提高性能,核心在于减少。侧重于一段时间内只执行一次。
可发现,防抖和节流都是针对高频率触发事件的优化,那么都应用在哪些场景下呢?
应用场景
防抖
- 用户在input框输入用户名内容时,校验用户名是否有效,可节省请求资源。
- 用户点击button时,避免用户多次点击,当然这里也可以采用第一次点击置灰的方案。
- window触发resize事件,不断调整窗口大小而导致多次调用resize事件。
节流
- 监听滚动事件,滑到底部自动加载更多。
- 计算鼠标移动距离。
- Dom元素的拖拽功能。
可发现,函数节流和防抖出现的场景一般都和DOM的事件监听有关,那么是怎么实现的?
手写代码
防抖
思路:防抖函数针对的是间隔,所以考虑使用setTimeout来模拟间隔时间,如果频繁触发,则刷新间隔时间。
/**
* @param {Function} func
* @param {number} wait
* @return {*}
*/
function debounce(fn, wait) {
// 闭包写法
let timeout = null
return function() {
// 如果在间隔时间内访问,就清除定时器
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(() => {
// 使用箭头函数和apply来绑定this指向,避免指向问题
fn.apply(this, arguments)
timeout = null
}, wait)
}
}
// 使用
function log(value) {
console.log(value)
}
debounce(log, 500)('参数')
节流
思路:节流函数针对是一段时间内只执行一次,所以考虑用setTimeout来设置间隔时间,如果频繁调用,setTimeout不为null的话就不执行。
/**
* @param {Function} func
* @param {number} wait
* @return {*}
*/
function throttle(fn, wait) {
// 闭包写法
let timeout = null
return function() {
// 如果在间隔时间内访问,不处理
if (timeout) {
return
}
timeout = setTimeout(() => {
// 使用箭头函数和apply来绑定this指向,避免指向问题
fn.apply(this, arguments)
timeout = null
}, wait)
}
}
// 使用
function log(value) {
console.log(value)
}
throttle(log, 500)('参数')
总结
防抖和节流都可以通过setTimeout来实现,目的都是节省计算资源,但需要注意的是,setTimeout是宏任务,如果js执行比较久,会影响到setTimeout的定时准确度。