函数节流也用到了高阶函数的知识,因为比较重要,所以单开了一个标题。
javascript中的函数在大多数情况下都是由用户主动调用触发的,除非是函数本身的实现不合理。但是在一些少数情况下,函数可能被很频繁的调用,而造成大的性能问题。
(1)函数被频繁调用的场景
1.window.onresize事件 2.mousemove事件 3.上传进度
(2)函数节流的原理
解决函数触发频率太高的问题,需要我们按照时间段来忽略一些事件请求。
(3)函数节流的代码实现
详情可以参考
Underscore.js#throttle
Underscore.js#debounce
简单实现:
将即将被执行的函数用steTimeout延时一段时间执行。如果该次延时执行还没有完成,就忽略掉接下来调用该函数的请求。
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 );
另一种实现函数节流的方法-分时函数
某些函数确实是用户主动调用的,但是因为一些客观的原因,这些函数会严重的影响页面的性能。
一个例子就是创建QQ好友列表。如果一个好友列表用一个节点表示,当我们在页面中渲染这个列表的时候,可能要一次性的网页面中创建成百上千个节点。
var ary = []; for ( var i = 1; i <= 1000; i++ ){ ary.push( i ); // 假设ary 装载了1000 个好友的数据 }; var renderFriendList = function( data ){ for ( var i = 0, l = data.length; i < l; i++ ){ var div = document.createElement( 'div' ); div.innerHTML = i; document.body.appendChild( div ); } }; renderFriendList( ary );
在短时间内网页面中大量添加DOM节点显然也会让浏览器吃不消。
这个问题的解决方案之一是下面的timeChunk函数:让创建节点的工作分批进行
//第一个参数是创建节点时需要的数据,第二个参数封装了创建节点逻辑的函数,第三个参数表示每一批创建节点的数量。 var timeChunk = function( ary, fn, count ){ var obj, t; var len = ary.length; var start = function(){ for ( var i = 0; i < Math.min( count || 1, ary.length ); i++ ){ var obj = ary.shift(); fn( obj ); } }; return function(){ t = setInterval(function(){ if ( ary.length === 0 ){ // 如果全部节点都已经被创建好 return clearInterval( t ); } start(); }, 200 ); // 分批执行的时间间隔,也可以用参数的形式传入 }; }; var ary = []; for ( var i = 1; i <= 1000; i++ ){ ary.push( i ); }; var renderFriendList = timeChunk( ary, function( n ){ var div = document.createElement( 'div' ); div.innerHTML = n; document.body.appendChild( div ); }, 8 ); renderFriendList();