防抖和节流----一看就懂 (附赠代码测试)
1. 防抖
概念:多次触发一个动作,只执行最后一个动作
应用:页面滚动触发事件、窗口缩放事件、多次点击按钮事件等等
测试代码:例如一个页面很长,你要监听鼠标滚轮的滚动事件,但是又希望鼠标滚轮事件结束之后再进行操作时,请参考下面的简单例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
/* 这里是样式 */
<style>
.container{
height: 2000px;
width: 600px;
margin: 0 auto;
background-color: gray;
}
</style>
<body>
/*这里是模拟的盒子*/
<div class="container"></div>
<script>
// 防抖
function debounce(fn, wait) {
//传入两个参数,
//参数 1 (fn)表示的是一个要执行的函数 ;
//参数 2 (wait)表示的是要等待的时间
var timeout = null;
//先定义一个标记,这个标记设置为 null
return function () {
//然后返回一个函数
if (timeout !== null) clearTimeout(timeout);
// 对这个标记进行判断
//如果这个标记不是空的情况下就执行后边的代码,
//但是很明显初始化的时候标记是空的,所以第一次是不执行的,
//直接走后边的步骤,定义这个变量为一个延迟函数,
//这个时候这个 timer 就会在规定的时间内等待执行,
//在规定时间内这个变量就是有意义的,所以再去操作这个函数的时候,
//就符合 if 判断了,这个时候就会清除这个延迟函数,
//这个延迟函数就不会执行,清除之后又重新加载一个延迟的函数,
//这样,每一次操作,总是在一定的时间之内清除上一个函数,
//然后开始一个新的延迟函数,就实现了在规定的时间之内反复的操作,
//只会执行最后一次操作的目的,这个就是防抖
timeout = setTimeout(fn, wait);
}
}
// 处理函数 这里是模拟需要执行的函数,譬如你需要的 ajax 网络请求;
// 这里就用一个简单的输出来表达
function handle() {
console.log(Math.random());
}
// 滚动事件
// 这里添加一个window 下的事件监听,后边放上这个防抖的函数,
// 防抖函数里边放上需要进行 防抖处理的函数和防抖的时间限制
window.addEventListener('scroll', debounce(handle, 1000));
</script>
</body>
</html>
恭喜你,成功看明白了~ 防抖 ~!
2. 节流
概念:在高频触发的操作下,稀释触发的频率;譬如本来要触发 100次/秒,现在减少到 1 次/秒
应用:页面滚动触发事件、窗口缩放事件、多次点击按钮事件等等
测试代码:例如一个页面要改变窗口尺寸,你要监听这个事件,但是又希望这个操作不要太频繁,请参考下面的简单例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
.container {
height: 2000px;
width: 600px;
margin: 0 auto;
background-color: gray;
}
</style>
<body>
<div class="container"></div>
<script>
// 首先我们要实现的效果是:在高频触发的操作下,稀释触发的频率,
// 譬如本来要触发 100次/秒,现在减少到 1 次/秒
function throttle(fn) {
// 这里是声明一个实现节流的函数,这个函数里边需要传递一个我们要节流的目标函数 fn
let canRun = true;
// 这里声明一个参数 canRun 变成 true
// 但是需要注意的是,并不是每一次事件都会触发这一个步骤
// 这一个步骤只会执行一次,但是 return 的函数会执行很多次
// 这个很类似于 react 框架中的高阶组件, 接受一个组件作为参数,然后返回一个组件,实际上运行的是返回的组件
return function () {
// 这里返回一个函数并执行
if (!canRun) return;
// 这里在要返回函数的内部做一个判断 如果这个 canRun 是 false 的话,直接结束这个函数不进行操作
canRun = false;
// 这里将 canRun 变成 false,变成 false 之后,继续执行后边的操作
// 后边每隔一一秒钟才会执行被节流的函数 fn,
// 并同时将 canRun 的值改成 true,成为 true 之后才能够再次执行fn,否则就直接结束
setTimeout(() => {
fn.apply(this,arguments);
// 问:这里 fn 为什么需要传递 this 对象,以及 arguments 参数?
// 思路:如果打印的话,this--->window; argument--->event
// 答:
// 1. 传递 this 对象是 apply 的固定用法,即,apply 的第一个参数是要传递的对象
// 2. 传递 arguments 是因为,我们下边的 sayHi()函数是一个普通函数,没有事件对象
// 而我们的resize 函数是一个事件函数,事件函数本身就有一个默认的参数 e ,
// 这里只是将 e 写成了 arguments ,这样写既能够符合 apply 的规范写法,
// 又能够给普通函数传递事件处理函数的默认参数 e
// 普通函数在拿到这个默认参数之后就能够进行相应的操作
canRun = true;
}, 1000);
};
}
// 模拟需要节流的目标函数
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
// 全局状态下监听
window.addEventListener('resize', throttle(sayHi));
</script>
</body>
</html>
恭喜你!看懂了 ### 节流 ###
如有不当之处,请各位朋友留言,批评指正!不胜感激! thank you~~~!