为什么使用防抖节流?
在前端开发中有一部分的用户行为会频繁的触发事件执行,而对于DOM操作、资源加载等耗费性能的处理,很可能导致界面卡顿,甚至浏览器的崩溃。函数节流(throttle)和函数防抖(debounce)就是为了解决类似需求应运而生的。
函数防抖就是在函数需要频繁触发情况时,只有足够空闲的时间,才执行一次。好像公交司机会等人都上车后才关门一样。他不会上来一个人就触发一次关门,而是等人陆续上来后等待一会再触发关门
我们以百度搜索框在输入完成后停顿一段时间便会进ajax请求为例子,我们实现输入框停止输入后再打印
//使用高阶函数,利用闭包封装
<!-- <script src="../../plugin/helpers.js"></script> -->
let oInp = document.getElementById('inp')
let timer = null
const debounce = (handler, delay) => {
let timer = null //利用闭包保存同一个timer
return () => {
let _self = this //取debounce执行作用域的this
let _arg = arguments //利用闭包保存参数数组
clearTimeout(timer) //不断的执行函数不断的清除定时器
timer = setTimeout(() => {
handler.apply(_self, _arg) //用apply指向调用debounce的对象,相当于_this.handler(args);
}, delay)
}
}
let shouValue = (e) => {
console.log(e,this.value)
}
oInp.oninput = debounce(shouValue, 1000);
函数节流就是预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。好像水滴攒到一定重量才会落下一样。
窗口调整(resize)
页面滚动( scroll)
抢购疯狂点击( mousedown)
目前我有两种思路:
//保证一个时间段内执行一次
const throttle = (handler, time) => {
let timer
return () => {
if (timer) {
return //判断如果有计时器不清零直接返回啥也不做
}
let _self = this //取throttle 执行作用域的this
let _arg = arguments //利用闭包保存参数数组
timer = setTimeout(() => {
handle.apply(_self, _arg)
timer = null
}, time)
}
}
//触发事件
window.onresize = () => handle()
//处理函数
let test = () =>console.log("a")
//调用throttle函数传参
let handle = myPlugin.throttle(test, 2000)
const throttle = (handler, time) => {
let t
return () => {
let _self = this //取throttle 执行作用域的this
let _arg = arguments //利用闭包保存参数数组
if (!t || Date.now() - t >= time ) {
handler.apply(_self , _arg );
t = Date.now(); //得到的当前时间戳
}
}
}
window.onresize = () => handle()
let test = () =>console.log("a")
let handle = myPlugin.throttle(test, 2000)
判断两种方式差异,我们只需要判断是否需要立即执行,我们就可以把节流的两种合并在一起
//保证一段时间只执行一次
constthrottle = (handler, time, immediately) => {
if (immediately === undefined) {
immediately = true //判断需要先立即执行
}
if (immediately) {
let t
return () => {
let _self = this //取throttle 执行作用域的this
let _arg = arguments //利用闭包保存参数数组
if (!t || Date.now() - t >= time) {
handler.apply(_self, _arg);
t = Date.now(); //得到的当前时间戳
}
}
}
else {
let timer
return () => {
if (timer) {
return //判断如果有计时器不清零直接返回啥也不做
}
let _self = this //取throttle 执行作用域的this
let _arg = arguments //利用闭包保存参数数组
timer = setTimeout(() => {
handle.apply(_self, _arg)
timer = null
}, time)
}
}
}
window.onresize = () => handle()
let test = () => console.log("a")
let handle = myPlugin.throttle(test, 2000,true)
tip:>(免费获取最新完整前端课程关注vx公众号:前端拓路者coder,回复:资料
如果这个文章对你有用的话,欢迎点赞转发关注,让更多的小伙伴看到呀,毕竟分享是一个程序员最基本的美德!!!
如果有不对的请大佬指教)