函数的防抖和节流
函数的防抖和节流
为什么要防抖/节流:
-
当我们前端在进行开发的时候,如果使用了onMouseOver,onMouseMove,resize这种执行非常迅速的方法,如果这些方法的回调非常的大,可能会造成浏览器的卡顿,严 重 的甚至会直接卡死。
-
而且如果短时间内大量的发起ajax请求,可能会对服务器产生一定的压力 造成网络的堵塞。
-
在这种情况下我们就需要用到函数的防抖或者节流对方法的回调进行一定限制
首先来看看事件是如何频繁触发的: 我们先写个示例文件:
HTML
<h1 class="h1">示例</h1>
<div class="box"></div>
css
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.h1 {
text-align: center;
font-size: 96px;
color: pink;
}
.box {
margin-top: 100px;
width: 80%;
height: 200px;
margin: 0 auto;
background: yellowgreen;
}
js
let h1 = document.querySelector('h1')
let box = document.querySelector('.box')
let num = 1
box.onmousemove = function () {
h1.innerHTML = num++
}
function add() {
console.log('123')
h1.innerHTML = num++
}
运行后:
接着我们将送鼠标从box左侧移动到box右侧来触发一下他的onmousemove事件
从左侧运行到右侧我大概花了1秒的时间 但是时间一共触发了127次,在这个案例内可能没什么问题,但是如果是ajax或者复杂的回调呢?假设 1 秒触发了 60 次,每个回调就必须在 1000 / 60 = 16.67ms 内完成,否则就会有卡顿出现。
为了解决这个问题,一般有两种解决方案:
- debounce 防抖
- throttle 节流
防抖(debounce)
首先我们先来说说防抖
- 如何通过防抖来解决上文中提到的问题
- 当用户在频繁触发事件时,方法只会在事件触发后的一段时候进行延迟执行,如果在事件执行中,又触发了这个事件,则将上一次的事件取消重新执行事件.
- 而在这里我们要实现上面的想法,就需要使用setTimeout(延时定时器)来辅助实现,延迟运行代码,第一次运行时开始计时,如果在运行时,再次触发,就将上次记录的延时定时器用clearTimeout清理掉,重新开始计时,如果计时期间事件没有被再次触发,等待延迟时间计时完毕,执行代码
接下来让我们使用这种方法将上边得代码处理一下:
//添加函数add
function add() {
h1.innerHTML = num++
}
// 非立即执行版
function debounce(fn, wait) {
let timer; // 使用闭包保存timer
return function () {
if (timer !== null) { //有timer则清空定时器
clearTimeout(timer)
}
timer = setTimeout(fn, wait) //申明定时器 在wait事件后执行fn方法
}
}
// box.onmousemove = debounce(add, 1000)
- 这种写法会在等待wait时间后再进行执行
//立即执行版
function debounce(fn, wait) {
let timer;
return function () {
if (timer) clearTimeout(timer)
let callNow = !timer; // 申明callnow为timer的非
timer = setTimeout(() => { timer = null }, wait) //wait时间后将timer变为null
if (callNow) add()
}
}
// box.onmousemove = debounce(add, 1000)
- 这种写法会先触发一次然后等待wait事件后可以再次触发
在进行处理以后我们再移动一次可以发现从左到右只触发了一次
解决了会触发多次得问题,接下来我们来看看节流
节流
什么是节流呢
- 当用户在进行频繁得触发事件的时候,每隔一段时间,只执行一次事件,
- 关于节流得实现,有两种主流的实现方式,一种是使用时间戳,一种是设置定时器
时间戳
function throttle(func, wait) {
let previous = 0;
return function () {
let now = Date.now(); //获取时间戳
if (now - previous > wait) { //判断时间戳减去previous是否大于wait 大于则是wait时间后触发的事件
add()
previous = now //将当前时间戳赋值给previous 方便下次比较
}
}
}
box.onmousemove = throttle(add, 1000)
定时器
function throttle(fn, wait) {
let timeout;
return function () {
if (!timeout) { //判断是否有timeout
timeout = setTimeout(() => { // 申明延时定时器
timeout = null; //wait时间后将timeout设为null
fn() //执行方法
}, wait)
}
}
}
box.onmousemove = throttle(add, 1000)
这就是我理解的一些浅显的节流和防抖 学习自冴羽大佬 若有问题 欢迎指出
转载自:https://juejin.cn/post/6884144032767803406