从字面上就能够理解,函数节流就是用来节流函数从而必定程度上优化性能的。例如,DOM 操做比起非DOM 交互须要更多的内存和CPU 时间。连续尝试进行过多的DOM 相关操做可能会致使浏览器挂起,有时候甚至会崩溃。尤为在IE 中使用onresize 事件处理程序的时候容易发生,当调整浏览器大小的时候,该事件会连续触发。在onresize 事件处理程序内部若是尝试进行DOM 操做,其高频率的更改可能会让浏览器崩溃。又例如,咱们常见的一个搜索的功能,咱们通常是绑定keyup事件,每按下一次键盘就搜索一次。可是咱们的目的主要是每输入一些内容搜索一次而已。为了解决这些问题,就可使用定时器对函数进行节流。javascript
某些代码不能够在没有间断的状况连续重复执行。第一次调用函数,建立一个定时器,在指定的时间间隔以后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另外一个。若是前一个定时器已经执行过了,这个操做就没有任何意义。然而,若是前一个定时器还没有执行,其实就是将其替换为一个新的定时器。目的是只有在执行函数的请求中止了一段时间以后才执行。html
var processor = { timeoutId: null, //实际进行处理的方法 performProcessing: function(){ //实际执行的代码 }, //初始处理调用的方法 process: function(){ clearTimeout(this.timeoutId); var that = this; this.timeoutId = setTimeout(function(){ that.performProcessing(); }, 100); } }; //尝试开始执行 processor.process();
好吧,看得确实有点迷糊。下面经过一个例子来详细说明,而且在这个基础模式之上作一个优化处理。java
例子场景:实现常见的搜索功能ajax
①没有使用函数节流的状况下,为input绑定keyup事件处理函数,在控制台输出我输入的内容。浏览器
测试主要代码:函数
HTMl: <input id="search" type="text" name="search"> JS: <script> function queryData(text){ console.log("搜索:" + text); } var input = document.getElementById("search"); input.addEventListener("keyup", function(event){ queryData(this.value); }); </script>
结果如图:性能
能够看出,这种状况下,每按下一个键盘键,就输出了一次。短短的一些内容,输出了14次,若是每一次都是一次ajax查询请求的话就发了14个请求了。在性能上的消耗可想而知。学习
②使用基本的函数节流模式的状况。测试
测试主要代码:优化
HTML: <input id="search" type="text" name="search"> JS: <script> function queryData(text){ console.log("搜索:" + text); } var input = document.getElementById("search"); input.addEventListener("keyup", function(event){ throttle(queryData, null, 500, this.value); // queryData(this.value); }); function throttle(fn,context,delay,text){ clearTimeout(fn.timeoutId); fn.timeoutId = setTimeout(function(){ fn.call(context,text); },delay); } </script
复制代码
结果如图:
能够看出,这种状况下,输入了好一些内容,只输出了一次,由于测试的时候设置了两次输入间隔是500ms,实际应用可根据状况设置。显然,这在性能上大大滴获得了优化。不过,这样的话,有一个新问题,以下图:
好吧,或许看不出端倪。其实问题就是,假如我不断地输入,输入了不少内容,可是我每两次之间的输入间隔都小于本身设置的delay值,那么,这个queryData搜索函数就一直得不到调用。实际上,咱们更但愿的是,当达到某个时间值时,必定要执行一次这个搜索函数。因此,就有了函数节流的改进模式。
③函数节流加强版
测试的主要代码:
复制代码
HTML:
<input id="search" type="text" name="search">
JS:
<script> function queryData(text){ console.log("搜索:" + text); } var input = document.getElementById("search"); input.addEventListener("keyup", function(event){ throttle(queryData, null, 500, this.value,1000); // throttle(queryData, null, 500, this.value); // queryData(this.value); }); function throttle(fn,context,delay,text,mustApplyTime){ clearTimeout(fn.timer); fn._cur=Date.now(); //记录当前时间 if(!fn._start){ //若该函数是第一次调用,则直接设置_start,即开始时间,为_cur,即此刻的时间 fn._start=fn._cur; } if(fn._cur-fn._start>mustApplyTime){ //当前时间与上一次函数被执行的时间做差,与mustApplyTime比较,若大于,则必须执行一次函数,若小于,则从新设置计时器 fn.call(context,text); fn._start=fn._cur; }else{ fn.timer=setTimeout(function(){ fn.call(context,text); },deley); } }
</script>
复制代码
测试结果如图:
显然,连续的输入,到必定时间间隔以后,queryData函数必然会被调用,可是又不是频繁的调用。这既达到了节流的目的,又不会影响用户体验。
④进一步的优化
进一步的话,就是能够在调用throttle函数以前,先对输入的内容进行判断,若其值为空、值不变都不用再调用。这里就不详说了。