Home > Article > Web Front-end > JavaScript中函数节流的理解_html/css_WEB-ITnose
函数节流,就是对会频繁触发的函数事件做一些限制,让这些函数可以在每隔一定的时间或者每次满足一定的条件下再触发。一般我们会给他起一个名字 throttle。也就是节流的意思。一般这样的函数有 resize事件、 ontouchmove事件等。
举个简单的例子
<!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8"> <title>测试函数节流</title> <style> #container{ width: 100%; height: 200px; border: 1px solid #646464; color: #000000; } </style></head><body > <div id="container"></div></body><script> function alertSomething(){ alert("您的鼠标正在移动"); }; document.getElementById("container").onmousemove = alertSomething;</script></html>
上面的代码就是简单的渲染出来一个 div然后给这个 div绑定了一个鼠标移动事件。但是我们在实际情况下,这种体验是不好的,因为这个事件会被十分频繁的触发。只要我们在这个 div上移动鼠标就会弹出这个阻塞性的事件 alert,所以我们希望每隔一定时间提醒一下“您的鼠标正在移动”。
下面写一个节流的函数 throttle()。
function throttle(func){ var timer; return function(){ var context = this; var args = arguments; clearTimeout(timer); timer = setTimeout(function(){ func.apply(context,args); },1000); } }
然后我们修改一下页面上的代码:
<!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8"> <title>测试函数节流</title> <style> #container{ width: 100%; height: 200px; border: 1px solid #646464; color: #000000; } </style></head><body > <div id="container"></div></body><script> function throttle(func){ var timer; return function(){ var context = this; var args = arguments; clearTimeout(timer); timer = setTimeout(function(){ func.apply(context,args); },1000); } } function alertSomething(){ alert("您的鼠标正在移动"); }; document.getElementById("container").onmousemove = throttle(alertSomething);</script></html>
下面我仔细解释一下这个节流函数。
函数利用闭包的形式存储了一个timer定时器变量,说实话我刚开始看别人在写这个节流函数的时候,也是不太容易懂,只是马马虎虎觉得是这样的,直到我亲自实现一遍,才明白。在这里建议亲自动手,丰衣足食~~
这个 timer变量当然也可以写在全局作用域中,但是可能会跟全局作用域中的变量产生冲突,所以在这里用闭包的形式来提供,防止它污染全局作用域。(看好多人在这里用“污染”,我想可能是如果有很多像 timer这样的变量都放在全局作用域中,到时候肯定容易与在全局作用域中常用的变量混淆。因为它毕竟只是在这个节流函数做定时器使用)。
然后就是 throttle函数返回的函数了。在这个函数中,要保存好传进来的执行上下文 this,和参数 arguments。应为我们要注意的是 setTimeout()函数中作用域是全局的,也就是 setTimeout中的 this指的是 window,在这里这个执行上下文其实就是 container对象,传入的参数就是鼠标移动这个事件的所有信息我们将这个 container这个对象的鼠标移动事件函数重写成 alertSomething这个函数。同时鼠标移动事件的信息也作为参数传入进去这一点也是我打印出他的相应信息后才恍然大悟,可能平时我们会理所当然的知道就是这样子的,但是为什么会这样子呢,我们知道了 alertSomething这个函数的参数和执行上下文是怎么传进去的,那直接调用 elementobj.onmousemove=function(){xxxxxx}这个函数的时候,上下文和参数是怎么传入进去的也应该是这样的原理吧。这是我的个人理解。
明白了上面的基本原理,我们再梳理一下节流函数发挥作用的过程:第一次调用这个节流函数的时候也就是第一次触发鼠标移动事件的时候,timer是没有的,所以 clearTimeout(timer)清理的定时器也是没有的,但是等第二次触发鼠标移动事件的时候,鼠标移动事件的处理函数就是一直是 throttle返回的函数了。首先会清理掉上次调用的时候的定时器,然后重新设置一个定时器。每次鼠标移动都是这样的处理过程,直到鼠标不再移动一秒钟后,定时器中的函数才被使用。
总之仔仔细细理解一下这个过程感觉真好!
但是如果我们需要自定义延迟的事件的话怎么办呢,下面我们可以再改进一下:
function throttle(func,delay){ var timer; return function(){ var context = this; var args = arguments; clearTimeout(timer); timer = setTimeout(function(){ func.apply(context,args); },delay); } }function dealMouseMove(){ alert("您的鼠标正在移动");};document.getElementById("container").onmousemove = throttle(dealMouseMove,500);