10.4 节流事件

代码清单10-11中实现的无穷滚动功能的主要问题是性能。尽管代码并不复杂,但checkScrollPosition()函数却需要计算页面和窗口的大小。由于某些浏览器中的scroll事件会在窗口滚动期间重复触发,因此计算过程会不断累积。最终结果就是导致页面忽急忽缓、反应迟顿。

浏览器中有几个原生事件都会频繁触发。最常见的事件有scrollresizemousemove。为了解决这个问题,就需要节流事件。这个技术会限制一些无谓的计算,即不是每次事件发生都计算,而是选择在部分事件发生时计算。我们可以在代码10-13的基础上实现这种技术,参见代码清单10-14。

代码清单10-14

  1. $(document).ready(function() {
  2. var timer = 0;
  3. $(window).scroll(function() {
  4. if (!timer) {
  5. timer = setTimeout(function() {
  6. checkScrollPosition();
  7. timer = 0;
  8. }, 250);
  9. }
  10. }).trigger('scroll');
  11. });

我们没有直接将 checkScrollPosition() 设置为 scroll 事件处理程序,而是使用 JavaScript的setTimeout函数,延迟250毫秒再调用它。更重要的是,我们会在执行任何代码之前先检查当前运行的计时器。因为检查一个简单变量的值速度极快,所以对事件处理程序的大多数调用都几乎能够立即返回。而对checkScrollPosition()函数的调用只会在计时器结束时才会发生,通常每次都要等250毫秒。

通过给setTimeout()设置一个合理的值,就能够在即时返馈与较高性能之间达成一个合理的折中。而我们的脚本也可以成为页面中一位安分守己的好公民。

其他节流方案

前面这种节流技术可以说既简单又实用。但是,节流的方案可不止那一种。根据被节流的操作的特点,以及与页面的典型交互方式,我们可以直接给页面创建一个计时器,而不是等事件开始时再创建,参见代码清单10-15。

代码清单10-15

  1. $(document).ready(function() {
  2. var scrolled = false;
  3. $(window).scroll(function() {
  4. scrolled = true;
  5. });
  6. setInterval(function() {
  7. if (scrolled) {
  8. checkScrollPosition();
  9. scrolled = false;
  10. }
  11. }, 250);
  12. checkScrollPosition();
  13. });

与前面的节流代码不同,这个轮询式的方案会调用JavaScript的setInterval()函数,每250毫秒检查一次scrolled变量的状态。不管什么时候发生滚动事件,scrolled都会被设置为true,以确保在下一次轮询时调用checkScrollPosition()。结果与代码清单10-14是类似的。

 在频繁重复的事件发生期间限制处理次数的第三种技术叫消除抖动(debouncing)。这种技术是以电子开关重复发送信号必需的后处理技术命名的,可以确保在发生多个事件的情况下,最终只会有一个事件实际地起作用。我们将在第13章介绍一个使用这种技术的例子。