您的位置:首页 > Web前端 > JavaScript

JavaScript性能优化技巧之函数节流

2016-08-26 15:34 615 查看
在写上一篇获取宽高度的博客的时候发现了一个问题,设置了
$(window).resize()
$(window).scroll()
的时候,函数调用的次数特别频繁,因为我写博客只是为了展现一个简单的例子,所以函数特别简单,但是当函数比较复杂的时候,那么频繁的调用这个函数将会对性能有特别大的损耗。

再写了简单的例子展现一下这个问题吧:

var n = 1;
$(window).resize(function(){
console.log(n++);
});


看一下运行的效果:

这是刚运行时候的界面:



下面是我简单的调整了一下浏览器的宽度:



在上面的例子中可以看出,这是简单的调整了一下窗口的位置,
$(window).resize()
方法就执行了96次,如果函数很复杂的话那么网页性能将会有极大的损耗,现在我们想要的是在调整页面之后执行一两次就行了,只要在调整完浏览器大小之后数据显示正确就可以了。

下面要介绍一种方法,叫做函数节流,函数节流的思想就是设置一个定时器,阻断连续执行的函数。

下面我们来简单的实现一下这个方法:

var n = 1;
var throttle = null;
$(window).resize(function(){
clearTimeout(throttle);
throttle = setTimeout(function(){
console.log(n++);
},500);
});


然后我再次调整浏览器的宽度:



可以看出来,通过上面的方法在调面后
$(window).resize()
方法只执行了整页一次。

接下来的任务就是把函数节流的方法封装一下,使它在任何地方都可以调用。

//封装函数
function throttle(method,context){
clearTimeout(method.throttle);
method.throttle = setTimeout(function(){
method();
},500);
}

//调用它
$(window).resize(function(){
throttle(lg,window);
});
var n = 1;
function lg(){
console.log(n++);
}


这样就可以在任意地方使用这个函数了,如果要自己设置延迟时间的话也可以修改函数自定义延迟时间,如下:

//封装函数
function throttle(method,context,time){
clearTimeout(method.throttle);
method.throttle = setTimeout(function(){
method();
},time);
}

//调用它
var n = 1;
$(window).resize(function(){
throttle(lg,window,300);
});
function lg(){
console.log(n++);
}


这样的做法简单高效,但是有一点不好的是它拓展了函数的属性,如果函数存在这个属性的话那么就会造成这个函数改变,还有一种使用闭包的方法来实现函数节流。

//封装函数
function throttle(method,delay){
var timer = null;
return function(){
clearTimeout(timer);
var context = this, args = Array.prototype.slice.call(arguments);
timer = setTimeout(function(){
method.apply(context,args);
},delay);
}
}
//调用它
//这里需要注意一下,因throttle()的返回值是一个函数,所以不能$(window).resize(function(){throttle(lg,window,300);})这样调用
//要直接将throttle当做函数赋给一个事件,像下面这样
$(window).resize(throttle(lg,300));
var n = 1;
function lg(){
console.log(n++);
}


上面两种方法都有各自的好处,具体想用哪种看自己的爱好。

在这种函数节流的情况下,拿窗口大小调整作为例子来说一下,如果我设置的延缓值为500毫秒,如果我调整浏览器大小的频率在500毫秒以内,那么这个函数就一直不会调用,每次延缓500毫秒,在还没有执行的时候我又调整了浏览器大小,那么js就会取消上一次
setTimeout()
设置的函数,重新设置一次新的
setTimeout()
在500毫秒之后执行,这样虽然做到了阻断连续重复的函数,但是函数却一直不能执行,这时候我们可以再做一次修改,让函数在触发以后在固定的时间内触发,即调整浏览器大小以后不管500毫秒以内你有没有再调整浏览器的大小,我们都让它在500毫秒后执行上次设置的函数,如果不断的改变浏览器大小,它就会每隔500毫秒执行一次,在很多时候是有这样的需求的,现在我们来更改一下上面的代码让它实现这样的需求。

//封装函数
function throttle(method,delay,duration){
var begin = new Date();
var timer = null;
return function(){
var current = new Date(), args = Array.prototype.slice.call(arguments), context = this;
clearTimeout(timer);
if(current - begin >= duration){
method.apply(context,args);
begin = current;
}else{
timer = setTimeout(function(){
method.apply(context,args);
},delay);
}
}
}

//调用这个方法
$(window).resize(throttle(lg,2000,2000));
var n = 1;
function lg(){
console.log(n++);
}


使用上面这个方法测试以后,发现只要在设置的固定间隔之后就会执行一次,不会出现一直不执行的情况。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息