(一)什么是抖动
举个例子,一个电商页面有一个输入框,当用户在输入框中输入所要查询的商品的时候,前端页面通过输入框 input 的 onchange 事件实时监听用户的输入内容,并调用涉及商品的接口,在下方列表中展示出相关搜索商品,大致效果如下
所以,当用户输入过快的时候,比如1s修改500次输入框的内容,前端 则 1s 调用500次后端商品列表接口,前端1s内把所查询的商品渲染500次在输入框下方列表中,速度如此过快,则会引起页面的抖动,结果:浏览器卡死
(二)函数防抖
当持续触发事件时,一定时间段内没有在触发事件,事件处理函数才会执行一次,如果设定的时间到来前,又一次触发了事件,就重新开始延时。(setTimeout)
例子:阿里巴巴输入框,一直按住键盘1在input里面输入1,不会调用接口,当键盘抬起多少毫秒后,调用下方商品列表接口。
通俗说法:比如一个小孩一直哭一直哭,家长说 只要保持住 2s 不哭,则给一块糖。设定时间为 2s , 这个事件一直只要保持了 2s 没有执行,则执行一次,这就是防抖。如果这期间又哭了,重新开始计时。前端持续调用该函数但该函数不执行,等着不调用了,保持住了n秒,执行一次。
例子2: 好闺蜜一直打你,等着她不打了,并且不打这个状态维持了1s,然后你再打她
(三)函数节流
当持续触发事件时,保持一定时间端内只调用一次执行函数。(setInterval)
例子: 好闺蜜一直打你,你在她打你的同时,每隔1s打她一次
这就是防抖与节流的定义
可以看一下 阿里巴巴(防抖)、淘宝(节流) 是怎么做输入框输入商品下方出现商品列表的,有没有用到防抖与节流技术
(四)防抖与节流的目的
避免回调函数的处理每一次都执行
(五)防抖与节流的使用场景
1. 防抖的使用场景:
(1)serch搜索,用户在不断输入值时,用防抖来节约请求资源
(2)window 触发 resize 的时候,不断调整浏览器的窗口大小,用防抖来只让其触发一次
(3)防止重复提交(现在用到方式:点击后禁用,不是防抖)
2.节流的使用场景
(1)鼠标不断点击触发,单位时间内只触发一次(mousedown)
(2)监听滚动事件,比如是否滑动到底部加载更多
(六)代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#container {
width: 300px;
height: 200px;
background: #000;
color: #fff;
line-height: 200px;
text-align: center;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var container = document.querySelector('#container')
var count = 0
function moving () {
container.innerHTML = ++count
}
// 代理模式 debounce 代理函数
// 两个参数 1. 回调函数 2. 时间间隔
function debounce(fun, time) {
var timer;
return function () {
clearTimeout(timer)
timer = setTimeout(fun, time)
}
}
container.onmousemove = debounce(moving, 2000) // 防抖
</script>
</body>
</html>
节流代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#container {
width: 300px;
height: 200px;
background: #000;
color: #fff;
line-height: 200px;
text-align: center;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var container = document.querySelector('#container')
var count = 0
function moving () {
container.innerHTML = ++count
}
function throttle(fun, time) {
var pre = 0
return function () {
var now = new Date()
// 当前时间 距离 上一次触发时间 大于设定值 执行一次(莫非只就是定时器原理??)
if (now - pre > time) {
fun()
pre = now // 重新设置 pre 为当前时间
}
}
}
container.onmousemove = throttle(moving, 1000) // 节流
</script>
</body>
</html>