JavaScript中的函数大多数状况下都是由用户主动调用触发的,除非是函数自己的实现不合理,不然咱们通常不会遇到跟性能相关的问题。但在一些少数状况下,函数的触发不是由用户直接控制的。在这些场景下,函数有可能被很是频繁地调用,而形成大的性能问题。下面将列举一些这样的场景。浏览器
(1) 函数被频繁调用的场景app
window.onresize
事件。咱们给window
对象绑定了resize
事件,当浏览器窗口大小被拖动而改变的时候,这个事件触发的频率很是之高。若是咱们在window.onresize
事件函数里有一些跟DOM节点相关的操做,而跟DOM节点相关的操做每每是很是消耗性能的,这时候浏览器可能就会吃不消而形成卡顿现象。函数
mousemove
事件。一样,若是咱们给一个div
节点绑定了拖曳事件(主要是mousemove
),当div
节点被拖动的时候,也会频繁地触发该拖曳事件函数。性能
上传进度。微云的上传功能使用了公司提供的一个浏览器插件。该浏览器插件在真正开始上传文件以前,会对文件进行扫描并随时通知JavaScript函数,以便在页面中显示当前的扫描进度。但该插件通知的频率很是之高,大约一秒钟10次,很显然咱们在页面中不须要如此频繁地去提示用户。this
(2) 函数节流的原理spa
咱们整理上面提到的三个场景,发现它们面临的共同问题是函数被触发的频率过高。插件
好比咱们在window.onresize
事件中要打印当前的浏览器窗口大小,在咱们经过拖曳来改变窗口大小的时候,打印窗口大小的工做1秒钟进行了10次。而咱们实际上只须要2次或者3次。这就须要咱们按时间段来忽略掉一些事件请求,好比确保在500ms内只打印一次。很显然,咱们能够借助setTimeout
来完成这件事情。code
(3) 函数节流的代码实现对象
关于函数节流的代码实现有许多种,下面的throttle
函数的原理是,将即将被执行的函数用setTimeout
延迟一段时间执行。若是该次延迟执行尚未完成,则忽略接下来调用该函数的请求。throttle
函数接受2个参数,第一个参数为须要被延迟执行的函数,第二个参数为延迟执行的时间。具体实现代码以下:blog
var throttle = function ( fn, interval ) { var __self = fn, // 保存须要被延迟执行的函数引用 timer, // 定时器 firstTime = true; // 是不是第一次调用 return function () { var args = arguments, __me = this; if ( firstTime ) { // 若是是第一次调用,不需延迟执行 __self.apply(__me, args); return firstTime = false; } if ( timer ) { // 若是定时器还在,说明前一次延迟执行尚未完成 return false; } timer = setTimeout(function () { // 延迟一段时间执行 clearTimeout(timer); timer = null; __self.apply(__me, args); }, interval || 500 ); }; }; window.onresize = throttle(function(){ console.log( 1 ); }, 500 );