/** * 函数节流方法 * @param Function fn 延时调用函数 * @param Number delay 延迟多长时间 * @param Number atleast 至少多长时间触发一次 * @return Function 延迟执行的方法 */ var throttle = function (fn, delay, atleast) { var timer = null; var previous = null; return function () { var now = +new Date(); if ( !previous ) previous = now; if ( now - previous > atleast ) { fn(); // 重置上一次开始时间为本次结束时间 previous = now; } else { clearTimeout(timer); timer = setTimeout(function() { fn(); }, delay); } } };
实践:
我们模拟一个窗口 scroll 时节流的场景,也就是说当用户滚动页面向下的时候我们需要节流执行一些方法,比如:计算 DOM 位置等需要连续操作 DOM 元素的动作
完整代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>throttle</title> </head> <body> <div> <div></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(); if ( !previous ) previous = now; if ( atleast && now - previous > atleast ) { fn(); // 重置上一次开始时间为本次结束时间 previous = now; clearTimeout(timer); } else { clearTimeout(timer); timer = setTimeout(function() { fn(); previous = null; }, delay); } } }; window.onscroll = throttle(testFn, 200); // window.onscroll = throttle(testFn, 500, 1000); </script> </body> </html>
我们用两个 case 来测试效果,分别是添加至少触发 atleast 参数和不添加:
// case 1 window.onscroll = throttle(testFn, 200); // case 2 window.onscroll = throttle(testFn, 200, 500);
case 1 的表现为:在页面滚动的过程(不能停止)中 testFN 不会被调用,直到停止的时候会调用一次,也就是说执行的是 throttle 里面 最后 一个 setTimeout ,效果如图:
case 2 的表现为:在页面滚动的过程(不能停止)中 testFN 第一次会延迟 500ms 执行(来自至少延迟逻辑),后来至少每隔 500ms 执行一次,效果如图
如上展示,我们要实现的效果已经介绍完毕并奉上了示例,望对有需要的朋友有所帮助。后续的一些辅助性优化读者可以自己琢磨,如:函数 this 指向,返回值保存等。总之仔仔细细理解一下这个过程感觉真好!
您可能感兴趣的文章: