防抖和节流是针对响应跟不上触发频率这类问题的两种解决方案。 在给DOM绑定事件时,有些事件我们是无法控制触发频率的。 如鼠标移动事件onmousemove, 滚动滚动条事件onscroll,窗口大小改变事件onresize,瞬间的操作都会导致这些事件会被高频触发。 如果事件的回调函数较为复杂,就会导致响应跟不上触发,出现页面卡顿,假死现象。 在实时检查输入时,如果我们绑定onkeyup事件发请求去服务端检查,用户输入过程中,事件的触发频率也会很高,会导致大量的请求发出,响应速度会大大跟不上触发。
针对此类快速连续触发和不可控的高频触发问题,debounce 和 throttling 给出了两种解决策略;
防抖:所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
节流:所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
防抖和节流的区别:
防抖:在高频发的事件调用时,每次将定义好的定时器清除掉,只有当高频发事件调用最后一次的时候,由于没有再调用该事件函数,没有清除定义的定时器,那么定时器将正常工作,即定时器等待时间内连续调用10次后显示1,连续调用20次后显示的还是1。通俗来讲就是,你要我搬十几块砖,我偷懒,我最后才搬一块。
节流:在高频发的事件调用时,不会清除定义好的定时器。假设你的定时器为1s,加入if判断语句,如果你高频发事件的调用间隔小于1s,那么你在这1s的定时器等待时间内调用的次数都当成一次,即连续调用10次后显示10、连续调用20次后显示20。注意,虽然是显示20、30 但是其将若干函数调用合成为一次,并在给定时间过去之后,调用一次(仅仅只会调用一次)。通俗来讲就是,你要我搬十几块砖,我搬,不过我每1s(定时器范围)才搬一块,多了我不干。
示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>javascript防抖和节流</title>
<style>
#content{
height: 150px;
line-height: 150px;
text-align: center;
font-size: 18px;
color: white;
background-color: gray;
}
</style>
</head>
<body>
<div id="content" >0</div>
<script>
var content = document.getElementById('content');
var num = 1;
function count(){ //基础操作
content.innerHTML = num++;
}
// content.onmousemove = function(){//没有防抖节流
// count();
// }
//防抖
function debounce(func, wait) {
var timeout;//声明一个定时器
return function () {
if (timeout){//每次调用函数都先清除定时器
clearTimeout(timeout);
}
timeout = setTimeout(function(){
func();//延迟调用函数
}, wait);
}
}
// content.onmousemove = debounce(count,500);
//节流
// 时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。
function throttle1(func, wait) {//时间戳版
var lastTime = 0;
return function() {
var currentTime = Date.now();
if (currentTime - lastTime > wait) {//如果调用时间间隔大于定时器规定时间,执行函数
func();
lastTime = currentTime;//重置上一次函数被调用时的时间
}
}
}
// content.onmousemove = throttle1(count,1000);
function throttle2(func, wait) {//定时器版
var timeout;//定义定时器
return function() {
if (!timeout) {//如果未定义定时器
timeout = setTimeout(function(){
func();
timeout = null;//释放定时器
}, wait)
}
}
}
content.onmousemove = throttle2(count,1000);
</script>
</body>
</html>