10.4 节流事件
代码清单10-11中实现的无穷滚动功能的主要问题是性能。尽管代码并不复杂,但checkScrollPosition()
函数却需要计算页面和窗口的大小。由于某些浏览器中的scroll
事件会在窗口滚动期间重复触发,因此计算过程会不断累积。最终结果就是导致页面忽急忽缓、反应迟顿。
浏览器中有几个原生事件都会频繁触发。最常见的事件有scroll
、resize
和mousemove
。为了解决这个问题,就需要节流事件。这个技术会限制一些无谓的计算,即不是每次事件发生都计算,而是选择在部分事件发生时计算。我们可以在代码10-13的基础上实现这种技术,参见代码清单10-14。
代码清单10-14
$(document).ready(function() {
var timer = 0;
$(window).scroll(function() {
if (!timer) {
timer = setTimeout(function() {
checkScrollPosition();
timer = 0;
}, 250);
}
}).trigger('scroll');
});
我们没有直接将 checkScrollPosition()
设置为 scroll
事件处理程序,而是使用 JavaScript的setTimeout
函数,延迟250毫秒再调用它。更重要的是,我们会在执行任何代码之前先检查当前运行的计时器。因为检查一个简单变量的值速度极快,所以对事件处理程序的大多数调用都几乎能够立即返回。而对checkScrollPosition()
函数的调用只会在计时器结束时才会发生,通常每次都要等250毫秒。
通过给setTimeout()
设置一个合理的值,就能够在即时返馈与较高性能之间达成一个合理的折中。而我们的脚本也可以成为页面中一位安分守己的好公民。
其他节流方案
前面这种节流技术可以说既简单又实用。但是,节流的方案可不止那一种。根据被节流的操作的特点,以及与页面的典型交互方式,我们可以直接给页面创建一个计时器,而不是等事件开始时再创建,参见代码清单10-15。
代码清单10-15
$(document).ready(function() {
var scrolled = false;
$(window).scroll(function() {
scrolled = true;
});
setInterval(function() {
if (scrolled) {
checkScrollPosition();
scrolled = false;
}
}, 250);
checkScrollPosition();
});
与前面的节流代码不同,这个轮询式的方案会调用JavaScript的setInterval()
函数,每250毫秒检查一次scrolled
变量的状态。不管什么时候发生滚动事件,scrolled
都会被设置为true
,以确保在下一次轮询时调用checkScrollPosition()
。结果与代码清单10-14是类似的。
在频繁重复的事件发生期间限制处理次数的第三种技术叫消除抖动(debouncing)。这种技术是以电子开关重复发送信号必需的后处理技术命名的,可以确保在发生多个事件的情况下,最终只会有一个事件实际地起作用。我们将在第13章介绍一个使用这种技术的例子。