防抖
防抖技术即是可以把多个顺序地调用合并成一次,也就是在一定时间内,规定事件被触发的次数。
通俗一点来说,看看下面这个简化的例子:
// 简单的防抖动函数function debounce(func, wait, immediate) { // 定时器变量 var timeout; return function() { // 每次触发 scroll handler 时先清除定时器 clearTimeout(timeout);//清除掉上一次的定时器回调函数,上次事件也就不会执行了。在500ms内,再次滚动,那上次的就清除掉了,不会执行。 // 指定 xx ms 后触发真正想进行的操作 handler timeout = setTimeout(func, wait); };};// 实际想绑定在 scroll 事件上的 handlerfunction realFunc(){ console.log("Success");}复制代码
采用了防抖动
window.addEventListener('scroll',debounce(realFunc,500));
封装上面的函数,更简洁
防抖动函数
function debounce(func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); };};var myEfficientFn = debounce(function() { // 滚动中的真正的操作}, 250);// 绑定监听window.addEventListener('resize', myEfficientFn);复制代码
防抖:
注意:上面的500ms,意思是:两次滚动事件的相隔时间必须大于500ms才能触发成功,而且是倒数第二次的事件触发成功的。如果所有的事件触发的时间间隔都小于500ms,那么就不会触发事件回调函数了,只有最后一次的事件回调能成功执行。复制代码
节流(Throttling)
-
防抖函数确实不错,但是也存在问题,譬如图片的懒加载,我希望在下滑过程中图片不断的被加载出来,而不是只有当我停止下滑时候,图片才被加载出来。又或者下滑时候的数据的 ajax 请求加载也是同理。
-
这个时候,我们希望即使页面在不断被滚动,但是滚动 handler 也可以以一定的频率被触发(譬如 250ms 触发一次),这类场景,就要用到另一种技巧,称为节流函数(throttling)。
- 节流函数,只允许一个函数在 X 毫秒内执行一次。
-
与防抖相比,节流函数最主要的不同在于它保证在 X 毫秒内至少执行一次我们希望触发的事件 handler。
-
与防抖相比,节流函数多了一个 mustRun 属性,代表 mustRun 毫秒内,必然会触发一次 handler ,同样是利用定时器,看看简单的示例:
// 简单的节流函数 function throttle(func, wait, mustRun) { var timeout, startTime = Date.parse(new Date());//重点,这里是在页面加载后就执行的。不是等到滚动才执行。 console.log(startTime); return function() { var context = this, args = arguments, curTime = new Date(); clearTimeout(timeout); // 如果达到了规定的触发时间间隔,触发 handler if(curTime - startTime >= mustRun){ func.apply(context,args); startTime = curTime;//重置开始时间startTime,把它设置成当前的时间 // 没达到触发间隔,重新设定定时器 }else{ timeout = setTimeout(func, wait); } }; }; // 实际想绑定在 scroll 事件上的 handler function realFunc(){ console.log("Success"); } // 采用了节流函数 window.addEventListener('scroll',throttle(realFunc,500,1000));复制代码
上面简单的节流函数的例子可以拿到浏览器下试一下,大概功能就是如果在一段时间内 scroll 触发的间隔一直短于 500ms ,那么能保证事件我们希望调用的 handler 至少在 1000ms 内会触发一次。注意:强调这句话:保证事件我们希望调用的 handler 至少在 1000ms 内会触发一次。最多也是一次。也就是说,在所有滚动事件的每两个相隔时间都加起来,从开始到结束滚动,每隔1000ms就是触发一次。比如从开始到结束,共经历1分钟,每隔1秒调用一次,总共大概调用60次。复制代码
参考链接: