看到这个标题就懵了, 你会有以下几个问题:什么是防抖?
什么是节流?
如何使用防抖?
如何使用节流?
什么时候需要用到防抖和节流?
为什么要用防抖和节流?
那我们就围绕这几个问题来讲一讲防抖与节流的两个概念和简单应用吧~ 我会在正文中给大家逐个解答问题
如果你不想看具体过程,也可以直接跳到总结,不过还是希望你慢慢看下去哦,因为这对你理解这两个操作很有帮助。
首先,在正文开始之前我们来看一个例子,来了解一下应用防抖和节流的初衷。
先放代码, 其中css代码中,实现导航栏悬停的属性,不明白的可以去看我的另一篇文章介绍,只需要一分钟不到就可以明白css3新属性position: sticky 一分钟实现 导航栏悬停功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.nav-bar{
height: 30px;
background: red;
/* 以下两个属性设置是为了实现导航栏的悬停 */
position: sticky;
top: 0;
}
</style>
</head>
<body>
<div class="nav-bar">我是导航栏</div>
<div>我是内容1</div>
<div>我是内容2</div>
<div>我是内容3</div>
<div>我是内容4</div>
<div>我是内容5</div>
<div>我是内容6</div>
<div>我是内容7</div>
<div>我是内容8</div>
<div>我是内容9</div>
<!-- 此处省略很多div标签 -->
<script>
window.onload = function () {
// 获取导航栏标签元素
let nav_bar = document.getElementsByClassName('nav-bar')[0]
//给window绑定滚动事件
window.onscroll = function () {
//每次触发滚动事件,打印导航栏离文档顶部的距离
console.log(nav_bar.offsetTop)
}
}
</script>
</body>
</html>
效果展示
我们可以看到, scroll事件是一个频发事件,我们只是简单的往下滚动, 但scroll 事件却触发了很多很多很多次。 但是我们的目的可能只是想获得滚动停下来以后导航栏距离文档顶部的距离, 我们并不需要滚动停止前那过程中变化的距离, 如果一直在滚动时去获取距离,这非常影响性能,这是我们就需要用到 防抖和节流了。
抖,听起来就是一个频繁触发的动作,我们可以想象我们在跑步,每跑一步就出很多的汗,我们跑的过程中,很想拿毛巾擦一擦汗,但是一想,如果刚擦完汗,跑几步就又出汗了,还不如不擦,我看看我等会还跑不跑,如果还跑,那我就一直不擦汗,如果我什么时候不跑了,我就开始擦一下汗。那么‘ 跑步 ’ 这个动作就可以看作我们上述代码中的滚动事件, ’ 擦汗 ’ 就可以看成scroll 事件的处理代码,即获取导航栏离文档顶部的距离。 那么防抖,就是我们滚动页面,刚要获取导航栏离文档顶部的距离,但是发现等会还要继续滚动,那么就先不获取了,等什么时候停止滚动了,再获取这个距离。
以上文字就是对防抖这个概念的一个形象的解释,希望大家反复阅读,理解了定义以后才方便理解下面的实现防抖的代码。
为了解决我们正文刚开始那个例子中,频繁获取导航栏离文档顶部的距离的现象,我们可以用一个setTimeout定时器来完成防抖功能
// 这里我们只修改js代码,其他都不变
<script>
window.onload = function () {
let nav_bar = document.getElementsByClassName('nav-bar')[0]
//初始化一个变量用于存储定时器
let timer = null
window.onscroll = function () {
//判断定时器是否还在运行
if(timer) {
//清除上一次事件创建的定时器
clearTimeout(timer)
}
//创建一个延迟为500ms的定时器并赋值给timer
timer = setTimeout(function () {
//定时器延迟过后获取导航栏离文档顶部的距离
console.log(nav_bar.offsetTop)
}, 500)
}
}
</script>
我们来解读一下这段代码:
现在,我们来看一下,运用了防抖之后滚动页面会有什么效果
我们可以很清楚的看到,在我们滚动的过程中,一直没有打印数据,直到我们停止以后, 控制台打印了导航栏离文档顶部的距离。这就是防抖的效果,现在你有没有对防抖有一个很深的印象了呢? 接下来我们来介绍一下第二种处理频繁触发事件的方法: 节流。
为了介绍节流的定义,我们继续使用跑步这一例子。想象我们在跑步,我们很热很热,在跑步的过程中,每隔几秒钟,拿毛巾擦一擦身上的汗。这里我们同样把 ’ 跑步 ’ 看作是 滚动页面的操作, 把 ’ 擦汗 ’ 看作是获取导航栏离文档顶部的距离的操作。那么,节流就是, 我们滚动页面,获取了一下导航栏离文档顶部的距离, 此时我们一直在滚动页面, 只不过我们刚获取过距离了,就先不获取了, 等距离上一次获取几秒后,我们再获取一次吧。
也请大家仔细体会节流的含义,方便理解下面的代码
节流的方法,有两种,一种是利用时间戳,另一种是利用定时器
代码如下:
// 同样的这里也是只需要修改js代码
<script>
window.onload = function () {
let nav_bar = document.getElementsByClassName('nav-bar')[0]
//初始化一个变量,用来存储上一次获取数据的时间戳
let last = 0
window.onscroll = function () {
//用来获取此时触发滚动事件时的时间戳
let now = Date.now()
//判断距离上次获取数据间隔了是否有1秒
if(now - last >= 1000) {
console.log(nav_bar.offsetTop)
//重置一下上一次获取数据时间戳
last = Date.now()
}
}
}
</script>
我们来解读一下这段代码:
现在,我们来看一下,利用时间戳节流之后滚动页面会有什么效果
可以很明显的看到,利用时间戳节流以后,获取数据操作没有像初始的那样频繁触发了,而是只要你在滚动,每隔一定时间进行一次触发,这个时间你是可以自己随意定义的。
代码如下:
// 这里也只需要修改js 代码
<script>
window.onload = function () {
let nav_bar = document.getElementsByClassName('nav-bar')[0]
//存放定时器
let timer = null
//存放上一个定时器的状态
let status = false
window.onscroll = function () {
// 判断上一个定时器是否执行完毕
if(status === false) {
// 给status 赋值true,代表定时器正在执行
status = true
timer = setTimeout(function () {
console.log(nav_bar.offsetTop)
clearTimeout(timer)
//定时器执行完毕,status赋值为false,告知执行完毕
status = false
}, 1000)
}
}
}
</script>
我们来解读一下这段代码:
现在,我们来看一下,利用定时器节流之后滚动页面会有什么效果
我们能很清楚的看到, 利用定时器节流的效果跟利用时间戳节流的效果差不多,如果非要说差别的话,就是利用时间戳节流,第一次滚动会立马获取一次数据,而利用定时器节流, 第一次获取数据会延迟一定时间。
简单做个总结吧,防抖和节流的区别:
相信你看完这篇文章,对防抖和节流有了很深的印象了吧, 其实在你的项目中,这两个操作很常用, 你也可以去找找以前做过的项目,看看哪里可以用到这两个操作的, 毕竟刚学完,还是需要练练手。关注我不迷路,以后每天给大家分享一篇关于前端面试频繁被问到的知识点~