持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情
一、前言
函数的节流(throttle)与防抖(debounce)都是为了节约函数性能的一种优化方案
二、节流
1. 概念
节流(throttle):让函数在单位时间内只调用一次,第一次调用生效,比如发送验证码(每隔一段时间)就比如游戏里的技能cd。
2. 对比使用节流前后
我们拿鼠标的移动事件举个例子
节流前
鼠标移动就会不停触发
<body>
<div class="box"></div>
</body>
<script>
var oBox = document.querySelector('.box')
var lastTime = 0
oBox.onmousemove = function(){
var nowTime = Date.now()
console.log(nowTime-lastTime)
lastTime = nowTime
}
</script>
<style>
.box{
width: 200px;
height: 200px;
background-color: pink;
margin: 200px auto;
}
</style>
节流后
不管鼠标事件出发多少次,时间限制每隔500毫秒触发一次
<body>
<div class="box"></div>
</body>
<script>
//我们是无法改变鼠标的移动事件的触发,只是让代码执行频率变少
var oBox = document.querySelector('.box')
var lastTime = 0
oBox.onmousemove = function(){
var nowTime = Date.now()
reduce = nowTime-lastTime
if(reduce<=500){return}
lastTime = nowTime
console.log(1)
}
</script>
<style>
.box{
width: 200px;
height: 200px;
background-color: pink;
margin: 200px auto;
}
</style>
3. 手写节流
<body>
<div class="box"></div>
</body>
<script>
//封装一个节流函数
function throttle(fn,time){
//绑定事件的时候,先初始化一个上一次的事件
var lastTime = 0
//这个函数是事件触发的时候真正调用的事件函数
return function(){
var nowTime = Date.now()
//相当于一个节流阀,只有满足才会真正的调用传进来的函数
if (nowTime - lastTime < time) {
return;
}
lastTime = nowTime;
/**
1.要考虑传进来的函数event问题:arguments
arguments所在的函数就是真正的事件函数,拥有实参event
把event事件对象传递给fn,传进来的函数(move)就可以使用event对象了
2.要考虑传进来函数的this指向问题:call(this)
**/
fn.call(this, arguments[0])
}
}
//节流后需要被调用的逻辑代码函数
function move(){
console.log(1)
console.log(event)
console.log(this)
}
var oBox = document.querySelector('.box')
//移动鼠标调用封装的节流函数
oBox.onmousemove = throttle(move,2000)
//滚动节流之后真正需要调用的函数
function scroll(){
console.log('滚了')
}
//滚动事件
window.onscroll = throttle(scroll,1000)
</script>
<style>
body{height:3000px}
.box{
width: 200px;
height: 200px;
background-color: pink;
margin: 200px auto;
}
</style>
最后验证
三、防抖
- 概念:防抖(debounce):让函数在单位时间内只调用一次,最后一次生效,比如搜索框,就比如游戏里最后一次回城被打断之前。
- 手写防抖
<body>
<input type="text" id="ipt">
</body>
<script>
//封装一个防抖函数
function debounce(fn,time){
var timer = null;
//事件函数
return function(){
//每次触发的时候,先把上一次的计时器清掉,然后重新开始计时
clearTimeout(timer)
//在计时器中 arguments是不符合的,要使用这个位置的arguments,先保存起来
var arg = arguments;
//保存外边的this 在计时器函数中使用
var that = this;
//每次触发事件,先不执行,要延迟一定的事件再执行
timer = setTimeout(function () {
fn.call(that, arg[0]);
}, time)
}
}
//逻辑函数
function inputChange(e) {
console.log("表单改变 请求数据");
console.log(e);
console.log(this);
}
var oIpt = document.querySelector('#ipt')
//调用防抖函数
oIpt.oninput = debounce(inputChange, 800)
</script>
验证结果
只在最后一次输入之后才调用
好了,以上就是本篇文章的分享,感谢阅读!