!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>throttle</title>
</head>
<body>
<div style="height:5000px">
<div id="demo" style="position:fixed;"></div>
</div>
<script>
var COUNT = 0, demo = document.getElementById('demo');
function testFn() {demo.innerHTML += 'testFN 被调用了 ' + ++COUNT + '次<br>';}
var throttle = function (fn, delay, atleast) {
var timer = null;
var previous = null;
return function () {
var now = +new Date();
console.log("now:"+now);
if ( !previous ) previous = now;
console.log("previous:"+previous);
if ( atleast && now - previous > atleast ) {
fn();
// 重置上一次开始时间为本次结束时间
previous = now;
clearTimeout(timer);
} else {
clearTimeout(timer);
timer = setTimeout(function() {
fn();
previous = null;
}, delay);
}
}
};
window.onscroll = throttle(testFn, 500);
//window.onscroll = throttle(testFn, 500, 100);
</script>
</body>
</html>
节流函数的意思:在延迟为 delay 的时间内,如果函数再次触发,则重新计时,这个功能和防抖动是一样的,第三个参数
atleast是一个时间间隔,表示在时间间隔大于 atleast后的一个函数可以立即直接执行。
注意:1.由于触发事件频繁调用函数时,每次都清除上次计时器,所以当滚动事件停止时,过了delay时间,才执行函数,所以,如果一直滚动不停止,只有一次对应函数,这是防抖动函数的缺点;
2.引入节流函数,在规定的时间内,执行对应函数,以上程序中存在闭包两个好处:(1)避免了全局变量污染,将变量封装在函数内部;(2)由于闭包变量不会在函数调用结束从内存清除,持续在内存中,所以previous会保存上次函数调用的值,使得previous成功保存上次函数调用结束的时间;
3.注意变量timer定义的位置,必须在闭包函数外面,否则如果在闭包函数内部,相当于重新定义一个计数器,而timer不会保存函数上次调用值,所以清除无效(清除时,timer=null),相当于计时器叠加,无法达到节流目的。