我发布了一个工具包,包括了防抖,节流,懒加载等工具函数。可以在 JS 和 TS 项目中使用 : https://www.npmjs.com/package/utils-h
GitHub :https://github.com/wtdsn/utils-h#readme
顾名思义,就是防止抖动的。比如验证码点击切换,用户快速点击了5次,但其实不用切换五次验证码,只需要切换一次就行了。那么就可以使用防抖。
防抖的特点是一定时间内的连续多次的触发,只会执行一次真正的回调。
节省资源,节省前端资源,提高性能;
如果要发起请求,还可以节省网络资源,降低服务器压力
节流是限制触发的频率,比如连续的滚动,scroll事件会被频繁的触发。如果这个时候,需要通过JS 去操作 DOM ,那么频繁的操作就会降低性能,导致页面卡顿
这个时候,就可能需要使用节流,限制它 16 ms 执行一次,如果不需要太及时,30ms执行一次也可以
节流的特点就是用户连续,频繁的触发某一事件时,真正的回调会以一定的频率进行执行。但总的次数比原本不节流的次数要少
节省资源,节省前端资源,提高性能;
如果要发起请求,还可以节省网络资源,降低服务器压力
其实和防抖一样,使用场景不同罢了
防抖和节流的区别:
防抖是在连续,多次的执行某个动作时,只真正的响应一次。它限制了响应的次数。
节流是在连续,多次的执行某个动作时,限制了响应的频率。
假如我们10s内连续,快速地触发某个事件,防抖只会触发一次,而节流会按照一定的频率触发多次
从使用场景来看,比如一个搜索按钮,用户连续点击多次,只需要执行一次就可以了。但是如果是 resize 时,我们希望内容的宽高也能够及时的更改去适应 resize 的变化,那么就需要使用节流
有些场景 ,防抖和节流都可以使用,看实际的效果需求!
主要的原理是利用闭包:对实际的回调函数进行封装,返回一个新的函数,利用闭包缓存的变量,控制回调是否执行
主要实现思路是设置一个定时器,如果在等待时间内重新触发,则取消定时器,重新计时
/**
* @param {any} wait
* @param {any} fun
*/
function debounce_simple(wait, fun) {
let timer
// 注意点1:,这里不能用箭头函数,因为箭头函数的 this 是函数设置的位置。于调用无关
// 并且无法使用 bind ,call 等
return function () {
clearTimeout(timer)
// 注意点2:这里需要使用箭头函数,this 使用这里的 this 和 arguments。
// 如果不是箭头函数,需要先把 this 和 arguments 缓存到其他变量使用
timer = setTimeout(() => {
fun.call(this, arguments)
}, wait)
}
}
基于简单版本,增加 immediate 参数,即第一次调用立即执行
/**
* @param {any} wait 等待时间
* @param {any} fun 回调函数
* @param {any} immediate 是否立即执行
* @returns {function} 返回一个新的函数
*/
function debounce(wait, fun, immediate = false) {
// 定时器
let timer = null
// 是否取消
let waiting = false
return function () {
// 等待中
if (waiting) {
clearTimeout(timer)
if (immediate) {
timer = setTimeout(() => {
waiting = false
}, wait)
} else {
timer = setTimeout(() => {
waiting = false
fun.apply(this, arguments)
}, wait)
}
return
}
waiting = true
// 立即执行
if (immediate) {
fun.apply(this, arguments)
timer = setTimeout(() => {
waiting = false
}, wait)
} else {
// 非立即执行
timer = setTimeout(() => {
waiting = false
fun.apply(this, arguments)
}, wait)
}
}
}
/**
* @param {any} dur
* @param {any} fun
* @return
*/
function throttle_simple(dur, fun) {
let waiting = false
return function () {
if (waiting) return
waiting = true
fun.call(this.arguments)
setTimeout(() => {
waiting = false
}, dur)
}
}
function throttle_simple2(dur, fun) {
let pre = 0
return function () {
let cur = Date.now()
if (cur - pre >= dur) {
fun.call(this.arguments)
pre = cur
}
}
}
节流复杂版,增加 endCall 参数,表示在末尾是否重新调用。
比如用户改变屏幕大小,需要调节元素,最后移动了 100px ,却刚好在等待时间内。导致元素没有及时调节
function throttle(dur, fun, endCall = true) {
let pre = timer = 0
return function () {
let cur = Date.now()
if (cur - pre >= dur) {
if (endCall) {
clearTimeout(timer)
timer = 0
}
fun.call(this.arguments)
pre = cur
return
}
if (endCall && !timer) {
timer = setTimeout(() => {
fun.call(this.arguments)
pre = cur
timer = 0
}, dur)
}
}
}