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

来源:互联网 发布:mysql 重命名字段 编辑:程序博客网 时间:2024/06/05 18:52

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

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

0 0
原创粉丝点击