函数节流也用到了高阶函数的知识,因为比较重要,所以单开了一个标题。
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();