- 概述
debounce
(防抖)和throttle
(节流)都是限制函数执行频次,可用于性能优化。throttle
强制一个函数随时间调用的最大次数,如“每100毫秒最多执行一次函数”;debounce
(强制一个函数在经过一段时间之后才会被调用,如“仅在100毫秒之后才会执行该函数”,如果按照100毫秒之后执行函数的规则来限制,那么事件会在触发100毫秒后再执行,如果100毫秒内又触发了,则重新计时。
- 应用场景
如果将滚动处理函数附加到DOM元素上,则尽可能会看到100多个事件被触发,如果事件做了大量繁杂的工作,会非常影响性能,出现延迟、假死、卡顿等现象,导致用户体验极差。所以一般用于window对象的scroll
、resize
事件,拖拽时的mousemove
事件,文字输入或自动完成的keyup
事件。
- 代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>防抖和节流效果演示</title>
<style type="text/css">
* {
box-sizing: border-box;
}
body {
background: #eee;
}
.area {
width: 300px;
height: 200px;
margin: 20px auto;
background: white;
position: relative;
}
.inside {
height: 200px;
position: relative;
overflow: auto;
}
.content {
height: 5000px;
}
.thing {
position: absolute;
top: 0;
left: 0;
width: 100%;
text-align: center;
background: #f06d06;
color: white;
padding: 10px;
}
.count {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div class="area area-1">
<div class="inside inside-1">
<div class="content content-1"></div>
<div class="thing thing-1">没有处理</div>
</div>
<div class="count count-1">0</div>
</div>
<div class="area area-2">
<div class="inside inside-2">
<div class="content content-2"></div>
<div class="thing thing-2">节流</div>
</div>
<div class="count count-2">0</div>
</div>
<div class="area area-3">
<div class="inside inside-3">
<div class="content content-3"></div>
<div class="thing thing-3">防抖</div>
</div>
<div class="count count-3">0</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script src="https://cdn.bootcss.com/lodash.js/4.17.12-pre/lodash.js"></script>
<script type="text/javascript">
var inside1 = $(".inside-1");
var thing1 = $(".thing-1");
var count1 = $(".count-1");
inside1.on("scroll",function(){
thing1.css('top',inside1[0].scrollTop);
count1.html(parseInt(count1.html())+1);
});
var inside2 = $(".inside-2");
var thing2 = $(".thing-2");
var count2 = $(".count-2");
inside2.on("scroll",_.throttle(function(){
thing2.css('top',inside2[0].scrollTop);
count2.html(parseInt(count2.html())+1);
},150));
var inside3 = $(".inside-3");
var thing3 = $(".thing-3");
var count3 = $(".count-3");
inside3.on("scroll",_.debounce(function(){
thing3.css('top',inside3[0].scrollTop);
count3.html(parseInt(count3.html())+1);
},100));
</script>
</body>
</html>
以上代码中使用了lodash
的throttle
和debounce
操作,代码执行后,在浏览器中执行后,即可直观看到调用效果差异
- 自定义
下面我们开始动手自己实现简单的防抖和节流函数
防抖-debounce
//防抖
function _debounce(fn,wait){
var timer = null;
return function(timer){
clearTimeout(timer);
timer = setTimeout(function(){
fn();
},wait)
}
}
//_debounce(_log,500);
//如果一直执行滚动之类的操作,且保证能够执行很久,那么有可能函数一直不会执行,所以需进一步改进
function _debounce(fn,wait,time){
var previus = null;
var timer = null;
return function(){
var now = new Date();
if(!previus){
previus = now;
}
if(now - previus > time){
clearTimeout(timer);
fn();
previus = now;
} else {
clearTimeout(timer);
timer = setTimeout(function(){
fn();
},wait);
}
}
}
function _log() {
console.log(1);
}
//_debounce(_log,500,2000);
节流-throttle
function _throttle(fn, time) {
let _self = fn;
let timer;
let firstFlag = true;
return function(){
let args = arguments;
let _this = this;
if(firstFlag){
_self.apply(_this,args);
return firstFlag = false;
}
if(timer){
return false;
}
timer = setTimeOut(function(){
clearTimeOut(timer);
timer = null;
_self.appply(_this,args);
},time || 500);
}
}
function _log() {
console.log(1);
}
//_throttle(_log,500);