JavaScript函数节流原理与多场景实现解析

作者:极速慢跑时间:2026-10-28 17:24:08浏览:366

本文深入解析JavaScript函数节流的核心原理,针对高频触发事件如resize、scroll及input输入等场景,探讨如何通过限制代码执行频率来优化浏览器性能,避免DOM重绘导致的卡顿或崩溃。文中提供了包括定时器封装、对象模式、闭包及时间戳判断在内的多种实现方案,帮助开发者根据实际需求选择最合适的节流策略。

函数节流的背景与必要性

在浏览器环境中,部分计算与处理操作的开销远高于其他操作。例如,DOM操作相比非DOM交互会消耗更多的内存与CPU资源。若连续执行过多的DOM相关操作,极易导致浏览器响应停滞,甚至引发崩溃。特别是在IE浏览器中使用onresize事件处理程序时,调整窗口大小会连续触发该事件。若处理程序内部包含DOM操作,这种高频变更往往会导致浏览器无响应或崩溃。

函数节流的核心原理

函数节流的核心思想在于:某些代码不能在无间断的情况下连续重复执行。首次调用函数时,会创建一个定时器,在指定的时间间隔后执行代码。当再次调用该函数时,系统会清除前一次的定时器并重新设置一个新的。如果前一个定时器已经执行完毕,此次操作便无实际意义;但若前一个定时器尚未执行,则将其替换为新的定时器。其目的是确保只有在函数请求停止一段时间后,代码才会真正执行。


 function throttle ( method , context ){
        clearTimeout ( method.tId );
        method.tId = setTimeout ( function () {
           method.call ( context );
         } , 100);
     }

基础应用场景:自适应高度

应用示例: 假设有一个<div/>元素,需要保持其高度始终等于宽度,代码实现如下:


 function resizeDiv(){
        var div = document.getElementById("mydiv");
        div.style.height = div.offsetWidth + "px";
      }
      window.onresize = function(){
        throttle(resizeDiv);
      }

在此示例中,调整大小的逻辑被封装在名为resizeDiv的独立函数中。onresize事件处理程序不再直接调用resizeDiv(),而是调用throttle()函数并传入resizeDiv。尽管用户通常感知不到性能差异,但这为浏览器节省了大量计算资源。

以下是其他技术人员的补充观点:

高频事件中的节流必要性

本文主要探讨工作中常用的函数节流技术。部分开发者可能对此缺乏足够重视,实际上,在JS开发中,许多场景都需要使用节流技术。最常见的场景包括屏幕尺寸调整(resize)、触摸滑动(touchmove)以及页面滚动(scroll)等事件。此前在讲解jquery判断页面滚动条方向及touchmove滑动方向的文章中,由于未涉及页面重绘,因此未使用JS函数节流。然而,当使用window.onresize时,resize事件会频繁触发,这直接关系到页面的重新绘制。因此,在window.resize场景下,强烈推荐使用函数节流技术。

JavaScript函数节流简介 如果前述长篇大论令人困惑,这里通过简单示例说明函数节流的概念。例如,当我们使用


 $(window).resize(function(){
      console.log("haorooms window resize");
    })

会发现:

函数节流的背景与必要性

控制台会输出多次结果。只需简单缩小窗口,就会不断触发该事件。

当页面中存在大量div时,不停的重绘操作在低版本IE等浏览器中极易导致崩溃。为避免此类情况,可采用函数节流。其基本思想是:首次调用函数时创建一个定时器,在指定时间间隔后执行代码;第二次调用时,清除前一个定时器并重新设置。若前一个定时器已执行,则无需再次操作;若尚未执行,则替换为新的定时器。目的是在函数停止调用一段时间后再执行。

基于对象模式的节流实现

使用对象模式可以实现如下代码:


var haoroomstest={
      timeoutId:null,
      performProcessing:function(){        
          console.log("resize");      

      },
      process:function(){
        clearTimeout(this.timeoutId);
        var that=this;
        this.timeoutId=setTimeout(function(){
          that.performProcessing();
        },500)
      }
    }

随后,我们可以通过以下方式调用:

$(window).resize(function(){ haoroomstest.process(); })

函数节流的背景与必要性

这种方式能够有效减少请求次数,降低DOM重绘频率,从而达到节流的目的。

函数节流的其他方式 除了上述对象模式,网络资料中还介绍了其他几种函数节流的方法,下面简要介绍:

其他常见节流实现方案

函数实现方式一


function throttle(method,context){
      clearTimeout(method.tId);
      method.tId=setTimeout(function(){
        method.call(context);
      },100);
    }

我们可以这样使用:


function resizeDIv(){
      console.log("haorooms")
    }

    $(window).resize(function(){
      throttle(resizeDIv)
    })

这与前文对象模式实现了相同的效果。

函数实现方式二

网上还有一种较为流行的节流实现方式,此处进行展示:


function throttle(method,delay){
      var timer=null;
      return function(){
        var context=this, args=arguments;
        clearTimeout(timer);
        timer=setTimeout(function(){
          method.apply(context,args);
        },delay);
      }
    }

调用方式如下:


function resizeDIv(){
      console.log("haorooms")
    }

   window.onresize=throttle(resizeDIv,500);

模糊搜索场景下的节流优化

新应用场景

在进行模糊搜索智能联想提示功能时,通常会在input元素上绑定keyup事件。由于不希望触发过于频繁,直接使用前述方法可能存在问题。因此,在原有函数基础上稍作调整,实现如下:


function throttle(method,delay,duration){
      var timer=null, begin=new Date();
      return function(){
        var context=this, args=arguments, current=new Date();;
        clearTimeout(timer);
        if(current-begin>=duration){
           method.apply(context,args);
           begin=current;
        }else{
          timer=setTimeout(function(){
            method.apply(context,args);
          },delay);
        }
      }
}

经过调整后,事件触发频率显著降低,从而提升了用户体验。

作者最新文章