一、 什么是防抖
防抖策略(debounce)是当事件被触发后,延迟 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。
(最后一次触发生效)*****
应用场景:
用户在输入框中连续输入一串字符时,可以通过防抖策略,只在输入完后,才执行查询的请求,这样可以有效减少请求次数,节约请求资源。典型的案例就是窗口大小的变化、模糊查询
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box {
width: 300px;
height: 300px;
background-color: rgb(115, 3, 3);
text-align: center;
line-height: 300px;
font-size: 100px;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
var box = document.querySelector('#box');
var i=0;
box.onmousemove=function(){
i++;
box.innerHTML=i;
}
</script>
</body>
</html>
或者用_.debounce(func, [wait=0], [options=])
_.debounce(func, [wait=0], [options=])
创建一个 debounced(防抖动)函数,该函数会从上一次被调用后,延迟 wait 毫秒后调用 func 方法。 debounced(防抖动)函数提供一个 cancel 方法取消延迟的函数调用以及 flush 方法立即调用。 可以提供一个 options(选项) 对象决定如何调用 func 方法,options.leading 与|或 options.trailing 决定延迟前后如何触发(注:是 先调用后等待 还是 先等待后调用)。 func 调用时会传入最后一次提供给 debounced(防抖动)函数 的参数。 后续调用的 debounced(防抖动)函数返回是最后一次 func 调用的结果。
注意: 如果 leading 和 trailing 选项为 true, 则 func 允许 trailing 方式调用的条件为: 在 wait 期间多次调用防抖方法。
如果 wait 为 0 并且 leading 为 false, func调用将被推迟到下一个点,类似setTimeout为0的超时。
参数:
1.func (Function): 要防抖动的函数。
2.[wait=0] (number): 需要延迟的毫秒数。
3.[options=] (Object): 选项对象。
4.[options.leading=false] (boolean): 指定在延迟开始前调用。
5.[options.maxWait] (number): 设置 func 允许被延迟的最大值。
6.[options.trailing=true] (boolean): 指定在延迟结束后调用。
返回:
(Function): 返回新的 debounced(防抖动)函数。
<script src="./js/lodash.min.js"></script>
<script>
var i = 0;
function move() {
i++;
box.innerHTML = i;
}
box.addEventListener('mousemove', _.debounce(move, 1000))
</script>
lodash.min.js在Lodash 简介 | Lodash中文文档 | Lodash中文网上下载
二、什么是节流
节流策略(throttle),顾名思义,可以减少一段时间内事件的触发频率。单位时间内,频繁触发事件,只执行一次 触发:有一个任务还在,取消触发(后两次取消)不会被打断
(第一次触发生效)*******
应用场景:
懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费 CPU 资源。典型的案例就是鼠标不断点击触发,规定在n秒内多次点击只有一次生效,用户登录
鼠标移动 mousemove 页面尺寸缩放resize 滚动条滚动scroll
例:
<script src="./js/lodash.min.js"></script>
<script>
var i = 1;
function move() {
i++;
box.innerHTML = i;
}
box.addEventListener('mousemove', _.throttle(move, 1000))
</script>
三、函数防抖和函数节流的对比
不管是函数节流还是函数防抖,减少的都是事件处理程序的调用频率,而不是时间的调用频率。
四、手写防抖和节流函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box {
width: 300px;
height: 300px;
background-color: rgb(115, 3, 3);
text-align: center;
line-height: 300px;
font-size: 100px;
}
</style>
</head>
<body>
<!-- box.addEventListener('mousemove', _.debounce(move, 1000)) 防抖
box.addEventListener('mousemove', _.throttle(move, 1000)) 节流
-->
<div id="box"></div>
<script>
var box = document.querySelector('#box');
var i = 1;
function move() {
i++;
box.innerHTML = i;
}
//1.手写防抖
/*
手写防抖
(1) 声明一个定时器变量
(2)当鼠标每次滑动都先判断是否有定时器,如果存在先清除以前的定时器
(3)如果没有定时器,则开启定时器,记得存在变量里面
4)定时器里写函数调用
*/
// function debounce(fn, t) {
// var timer;
// return function () {
// if(timer){
// clearTimeout(timer)
// }
// timer = setTimeout(function () {
// fn()
// }, t);
// console.log(timer);
// }
// }
// box.addEventListener('mousemove', debounce(move, 1000)) //防抖
//2.手写节流
/*
(1) 声明一个定时器变量
(2)当鼠标每次滑动都先判断是否有定时器,如果有定时器,则不开启新的定时器
(3)如果没有定时器,则开启定时器,记得存到变量里面
--- 定时器里写函数调用
-- 定时器里面把定时器清空 timer=null
*/
function throttle(fn, t) {
var timer = null;
return function () {
if (!timer) {
timer = setTimeout(function () {
fn();
timer = null;
}, t);
console.log(timer);
}
}
}
box.addEventListener('mousemove', throttle(move, 1000)) //节流
</script>
</body>
</html>