事件节流 & 节流事件
在浏览器 DOM 事件里面,有一些事件会随着用户的操作不间断触发。比如:resize、scroll、mousemove。这并不是我们想要的,因为有的时候如果事件处理方法比较庞大,DOM 操作比如复杂,还不断的触发此类事件就会造成性能上的损失,导致用户体验下降(UI 反映慢、浏览器卡死等)。所以,这个时候,事件节流就显得相当重要了。
在这里我将列举几条节流方案
1.javascript 提供了throttle()函数,它的实现如下
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); } } };
我没有考证这个函数的具体实现,暂且已上文做为一种节流方法
2.第二种节流方案
(function($) { var timer = 0; $(window).scroll(function() { if (!timer) { timer = setTimeout(function() { //一些操作; timer = 0; }, 250); } }).trigger('scroll'); }); })(jQuery);
这里虽然用到了JQuery 的符号,但是没有什么关系。我想说的是,这种节流方案,是我比较赞同的。第一条节流方案,虽然也达到了相同的结果,但是在不断 创建和删除 定时器。这并不见得对性能有多友好。相比较,第二种方案,通过设置一个开关,在第一次滚动时通过判断进入if语句,这时改变了timer变量的值,使接下来的scroll事件,都不能进入if,执行事件的操作。定时器事件执行之后,timer变量又被赋值为0。这样又能进入if判断语句。这个开关机制相比较,简单,更实用
3.第三种节流方案
(function($) { var scrolled = false; $(window).scroll(function() { scrolled = true; }); setInterval(function() { if (scrolled) { //一些操作 scrolled = false; } }, 250); })(jQuery);
这种节流方案也是一种奇思妙想,将事件的处理函数放在一个setInterval()函数中,每间隔一段事件监测一次是否发生了scroll事件,然后执行,而scroll事件只执行一个开关的作用,这个想法很好。
4.在前面的基础上,我们再加点JQuery事件,问题会更简单。
我们想创建一个特殊事件,这样以后我们的项目中,直接可以绑定这个事件,就不用再判断什么条件了
(function() { $.event.special.throttledScroll = { setup: function(data) { var timer = 0; $(this).on('scroll.throttledScroll', function() { if(!timer) { timer = setTimeout(function() { $(this).triggerHandler('throttledScroll'); timer = 0; }, 200) } }) }, teardown: function() { $(this).off('scroll.throttledScroll'); } } })(jQuery); $(document).ready(function() { var i = 0 $(window).on('throttledScroll', function() { console.log(i); i++; }) });
这里我创建了一个jQuery事件,在这个事件内部做了之前的判断,所以后面,我只用绑定我定义的这个特殊事件就可以监控scroll事件了,并且还是经过节流处理的。
谢谢关注