JavaScript函数节流

ivdmjxeoyb 7年前
   <h3><strong>函数节流</strong></h3>    <p>函数节流就是节约函数的调用,让函数少执行几次,一般用在onmousemove,onresize这种我们只要稍微一动就会砰砰砰执行多次的事件处理函数上。如果处理函数很复杂有执行很多次就很耗性能关键了有的是没有必要执行的。</p>    <p>我们先说一个经常遇见的情况,鼠标放在按钮上显示下拉菜单,鼠标离开下拉菜单消失,通常我们这么写:</p>    <pre>  <code class="language-javascript">//title表示标题元素,content表示下拉菜单  $("#title").hover(function(){    $("#content").show();  },function(){    $("#content").hide();  })  </code></pre>    <p>当我们快速划过的时候,会看到下拉菜单会先出现然后立即隐藏传说中的闪一下,我们知道用户快速划过时一般情况下并不是要查看下拉菜单的,所以我们要避免下拉菜单闪一下的这种事,通常我们的做法就是加一个定时器:</p>    <pre>  <code class="language-javascript">var timer;  $("#title").hover(function(){      timer = setTimeout(function(){          $("#content").show();      },100)  },function(){      clearTimeout(timer);      $("#content").hide();  })  </code></pre>    <p>这样当我们想查看菜单时只要把鼠标放在标题元素上下拉菜单就出现了,当我们鼠标快速划过标题元素时并不会出现下拉菜单元素,避免了菜单闪一下的尴尬事。</p>    <p>继续介绍函数节流。函数节流也是这个套路,假如我们想对onresize事件进行处理(假设handler是一个很复杂的处理函数):</p>    <pre>  <code class="language-javascript">$(window).resize(handler);  var a = 1;  function handler(){      console.log(a++);  }  </code></pre>    <p>我们在改变窗口大小的时候只要稍微动一下处理函数就会执行十几次,这其实是完全没必要的,如果处理函数有很多的DOM操作,这是很耗性能的,所以我们要尽可能的减少事件处理函数的执行次数。</p>    <p>我们也像上一个例子一样使用一个定时器来实现:</p>    <pre>  <code class="language-javascript">$(window).resize(handler);  var a = 1;  var timer;  function handler(){      timer&&clearTimeout(timer);      timer = setTimeout(function(){          console.log(a++);      },50)  }  </code></pre>    <p>在我们改变浏览器大小的过程中事件处理函数并没有执行,只有当停止时才会执行我们的处理函数。为了使用方便可以封装成一个函数:</p>    <pre>  <code class="language-javascript">$(function(){      $(window).resize(function(e){          defer(this,200,handler)(e);      })  })  function handler(e){      console.log(e);  }  /**  **fn表示事件处理函数  **_this表示事件处理函数中的this指向  **delay表示延迟时间  */  function defer(_this,delay,fn){      return function(){          fn.timer&&clearTimeout(fn.timer);          var arg = arguments;          fn.timer = setTimeout(function(){              fn.apply(_this,arg);          },delay)      }  }   </code></pre>    <p>这种方式在处理onresize事件上还算是实用的但是在onmousemove上就会感觉很尴尬了,对于onmousemove我们通常处理都是标识出一个物体的轨迹,如果用上面的方式那么在移动的过程中总是清除定时器导致处理函数不执行,当鼠标停止时处理函数才开始执行,就看到物体直接从起点跳到终点,过程无迹可寻!</p>    <p>为了记录物体运动的轨迹我们需要在一定的间隔内就执行一次onmousemove的事件处理函数:</p>    <pre>  <code class="language-javascript">$(function(){      $("#demo").bind("mousedown",function(e){          var _this = this;          var left = $(this).offset().left;          var top = $(this).offset().top;          var downX = e.pageX;          var downY = e.pageY;          var disX = downX-left;          var disY = downY-top;          $(document).bind("mousemove",function(e){              defer(_this,200,handler)(e,disX,disY);                      })          $(this).bind("mouseup",function(e){              handler.timer&&clearInterval(handler.timer);              $(document).unbind("mousemove");              $(this).unbind("mouseup");          })      })  })  function handler(e,disX,disY){      var currentX = e.pageX;      var currentY = e.pageY;      $(this).css({"top":currentY-disY+"px","left":currentX-disX+"px"});      console.log(1)  }  /**  **fn表示事件处理函数  **_this表示事件处理函数中的this指向  **delay表示延迟时间  **interval表示函数执行的间隔默认50ms  */  function defer(_this,delay,fn,interval){      return function(){          fn.timer&&clearTimeout(fn.timer);          var arg = arguments;          var _interval = interval || 50;          fn.start?"":fn.start=+new Date();          var current = +new Date();          if(current-fn.start>=_interval){              fn.start = current;              fn.apply(_this,arg);          }else{              fn.timer = setTimeout(function(){                  fn.apply(_this,arg);              },delay)          }          }  }  </code></pre>    <p> </p>    <p> </p>    <p>来自:http://www.cnblogs.com/shinhwazt/p/6021366.html</p>    <p> </p>