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

       在写上一篇获取宽高度的博客的时候发现了一个问题,设置了$(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++);
}

        使用上面这个方法测试以后,发现只要在设置的固定间隔之后就会执行一次,不会出现一直不执行的情况。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值