JavaScript性能优化8——防抖与节流
Posted JIZQAQ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript性能优化8——防抖与节流相关的知识,希望对你有一定的参考价值。
目录
一、引入
为什么需要防抖和节流
我们现在JS主要是在浏览器下运行,涉及到很多人机交互的操作。假设一个场景,我们打开的网页有一个轮播图,我们对左右切换的按钮疯狂点击。按钮是绑定了操作的,那么每次我们点击这个按钮被监听到后就会执行代码,有部分内存会被使用,性能也有所消耗。这就是所谓的高频次触发的场景。在这种场景下,我们希望事件对应的监听不需要立即或者说反复被触发,这样我们就需要对其进行防抖和节流的操作。
使用场景
- 滚动事件
- 输入的模糊匹配
- 轮播图切换
- 点击操作
- ……
浏览器默认情况下都会有自己的监听事件间隔,比如Chrome浏览器监听间隔是4-6ms。如果检测到多次事件的监听执行,那么就会造成不必要的资源浪费。
概念
防抖:对于高频操作来说,我们只希望只识别一次,可以认为认为是第一次或者最后一次。
节流:对于高频操作,我们可以自己设置频率,让本来会执行很多次的事件触发,按照我们定义的频率减少触发次数。
二、防抖函数实现
场景
有一个按钮,我们对其进行高频触发,但是希望只识别一次。
原始代码
这个代码下,就是点击一次执行一次。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防抖函数实现</title>
</head>
<body>
<button id="btn" >点击</button>
<script>
//找到目标元素
var oBtn = document.getElementById('btn')
oBtn.onclick = function ()
console.log('点击了')
</script>
</body>
</html>
防抖函数代码
里面具体的思路和每一块是干什么的,都写在代码注释里面了,这边就不展开了。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防抖函数实现</title>
</head>
<body>
<button id="btn" >点击</button>
<script>
//找到目标元素
var oBtn = document.getElementById('btn')
// oBtn.onclick = function ()
// console.log('点击了')
//
/**
* handle 要执行的操作
* wait 事件触发后多久开始执行
* immediate 控制执行第一次还是最后一次,如果是false就执行最后一次,如果是true就执行第一次
*/
// 其实这些参数我们可以考虑给他们添加默认值比如wait = 300, immediate = false。
// 但是定义一个函数给它的形参赋予一个默认值,这样的话它整个函数体里的代码将来如果出现一些变量定义之后,会有一些比较变态的机制.这边不做讨论,所以先不设置默认值了
function myDebounce (handle,wait,immediate)
//参数类型判断及默认值处理
if(typeof handle !== 'function') throw new Error('handle must be a function')
if(typeof wait === 'undefined') wait = 300
if(typeof wait === 'boolean')
immediate = wait
wait = 300
if(typeof immediate === 'undefined') immediate = false
// 所谓的防抖效果,我们想要实现的是有一个”人“,可以管理handle的执行次数
// 如果我们想要执行最后一次,那意味着无论我们当前点击了多少次,前面的N-1次都没有用
let timer = null
return function proxy(...args)
let self = this
init = immediate && !timer
clearTimeout(timer)
timer = setTimeout(() =>
timer = null
//只有我们的immediate为false才执行下面这个代码,否则就不执行【原本其实就是handle(),但是为了拿到this和mouseEvent所以改成下面这个样子】
!immediate ? handle.call(self, ...args) : null
,wait)
//如果当前传进来的是true,就表示我们需要立即执行
// 如果想要实现只在第一次执行,可以添加上timer为null作为判断,因为只要timer为null,就意味着没有第二次
init ? handle.call(self, ...args) : null
// 定义事件执行函数,这里的ev是点击的MouseEvent,this是button元素
function btnClick(ev)
console.log('点击了', this, ev)
// 当我们执行了按钮点击之后就会执行防抖函数返回的proxy
//oBtn.onclick = myDebounce(btnClick,false)
oBtn.onclick = myDebounce(btnClick,200,true)
</script>
</body>
</html>
三、节流函数实现
场景
一个页面我们往下滚动,触发相应事件。
原始代码
这个代码下,我们只要做出滚动的动作就会被监听到,不断触发scrollFn方法。但是这其实是会造成资源浪费的,我们并不需要这么高频次的响应触发。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节流函数实现</title>
<style>
body
height:5000px
</style>
</head>
<body>
<script>
// 定义滚动事件监听
function scrollFn()
console.log('滚动了')
window.onscroll = scrollFn
</script>
</body>
</html>
节流函数代码
我们这里的节流指的是在自定义的一段事件内让事件进行触发
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节流函数实现</title>
<style>
body
height:5000px
</style>
</head>
<body>
<script>
// 节流: 我们这里的节流指的是在自定义的一段事件内让事件进行触发
function myThrottle(handle,wait)
if(typeof handle !== 'function') throw new Error('handle must be a function')
if(typeof wait === 'undefined') wait = 400
let previous = 0 // 定义变量记录上一次执行的时间
let timer = null // 用来管理定时器
return function proxy(...args)
let self = this
let now = new Date()
let interval = wait - ( now - previous)
if(interval <= 0)
//万一很巧的定时器延迟到的操作和我们的点击同时进行
clearTimeout(timer)
timer = null
//非高频次操作,可以执行handle
handle.call(self, ...args)
previous = new Date()
//当我们发现系统中有一个定时器了,就不需要再开启定时器了
else if(!timer)
//这次操作发生在我们定义的频次时间范围内,不应该执行
// 这个时候可以自己定义一个定时器,让handle在interval之后去执行
timer = setTimeout(() =>
clearTimeout(timer)// 这个操作知识将系统中的定时器清楚了,但是timer中的值还在,所以需要手动吧timer = null
timer = null
handle.call(self, ...args)
previous = new Date()
,interval)
// 定义滚动事件监听
function scrollFn()
console.log('滚动了')
//window.onscroll = scrollFn
window.onscroll = myThrottle(scrollFn,600)
</script>
</body>
</html>
参考资料
1.拉勾网 《大前端训练营》课程
以上是关于JavaScript性能优化8——防抖与节流的主要内容,如果未能解决你的问题,请参考以下文章