Javascript函数式编程之节流函数

一、前言

不知道大家是否遇到过这样一个问题,对于一些函数或者事件它们能够频繁地触发,比如说下面的滚动事件,

window.onscroll = function(){
    console.log("触发了事件");
}

当然,需要把body的高度设置高一点(比如说10000px),不然无论你怎么滚动,都看不到效果的~
只要我们滚动鼠标的滚轮或者是拖拽页面的滚动条,上面的事件就能触发,而且非常地频繁(这一点,大家可以自己去尝试一下,通过观察控制台就能体会到了)。
又比如说窗口的onresize事件,

window.onresize = function(){
    console.log("触发了事件");
}

只要我们改变窗口的大小,它也能够频繁地触发。说到onresize我就想起了我之前做的一个小球随机运动demo,个人觉得还算可以,所以想分享给大家。
demo演示地址
github源码地址
然而在一些场景下,我们是不希望这种事情发生的,对于这种频繁发生的事件,可以通过节流控制它的频率。

二、节流函数(Throttle)

在说节流之前,我想先提一下水龙头,我相信大家肯定对它不陌生,无论是刷牙洗脸洗碗洗澡什么的都用得着它,在生活中那是无处不在!当我们把水龙头放得很开的时候,那水哗啦啦的流,把它拧紧到一定程度后,水是呈滴状地滴落,而且间隔时间相同。聪明的小伙伴们或许已经发现其中的奥秘了,没错,如果把频繁触发的事件比作水流的话,那么节流函数就是水龙头,能够控制事件触发的频率,也就是说,让原本频繁触发的事件变成间隔相同的时间后才能被触发。
基于上面的思路,我们可以封装一个函数,也就是节流函数,用来控制事件的发生频率,

function throttle(fn,time){
    var startTime = new Date();//初始时间
        return function(){
            var time_ = (new Date() - startTime) >= time;//判断时间间隔是否大于传入的time值,返回布尔值
            if(time_){
                fn.apply(this);
                startTime = new Date();//函数执行完后更新初始时间的值
        }
    }
}

有了节流函数之后,我们再对上面的事件进行修改如下:

function throttle(fn,time){
    var startTime = new Date();
        return function(){
            var time_ = (new Date() - startTime) >= time;
            if(time_){
                fn.apply(this);
                startTime = new Date();
        }
    }
}
function fn(){
    console.log("触发了事件");
}
window.onscroll = throttle(fn,1000);

同样,别忘了设置body的高度~,fn于是每隔一秒触发一次,并不会频繁地触发了,大家可以自己去试试。

三、节流在无缝轮播中的应用

在无缝轮播中,如果用户疯狂地点击下一张图片按钮的话,那么会出现一个问题,就是上一个动画还没执行完,下一个动画就开始执行了,结果就是会导致整个轮播过程显得非常混乱,用户体验也会下降,就像下面的动图演示一样,
没有节流的无缝轮播
为了解决上述问题,可以用节流控制每次点击事件发生的频率,达到只有在上一张图片的动画执行完了,下一次点击事件才能触发的效果,以下是比较简单的无缝轮播演示demo和代码部分,
无缝轮播演示
代码部分:

/* css代码 */
body{
    background-color: #333;
}
.wrap{
    overflow: hidden;
    position: relative;
    width: 700px;
    height: 450px;
    margin: 100px auto 0;
}
.wrap .btn{
    position: absolute;
    top: 50%;
    z-index: 1;
    width: 50px;
    height: 80px;
    margin-top: -40px;
    background-color: rgba(0,0,0,.5);
    color: #fff;
    text-align: center;
    line-height: 80px;
    cursor: pointer;
}
.wrap .left{
    left: 0;
}
.wrap .right{
    right: 0;
}
ul{
    transition-timing-function: linear;
    position: absolute;
    left: 0;
    top: 0;
    list-style: none;
    margin: 0;
    padding: 0;
    width: 3500px;
    height: 100%;
}
li{
    float: left;
    width: 700px;
    height: 100%;
}
li:nth-of-type(1){
    background: url("images/01.jpg") no-repeat center/cover;
}
li:nth-of-type(2){
    background: url("images/02.png") no-repeat center/cover;
}
li:nth-of-type(3){
    background: url("images/03.png") no-repeat center/cover;
}
li:nth-of-type(4){
    background: url("images/04.png") no-repeat center/cover;
}
li:nth-of-type(5){
    background: url("images/01.jpg") no-repeat center/cover;
}
<!-- html代码 -->
<div class="wrap">
<div class="btn left">&lt;</div>
<div class="btn right">&gt;</div>
<ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
</div>
//js代码
(function(){
    var oUl = document.getElementsByTagName("ul")[0],
        aButton = document.getElementsByClassName("btn"),
        aLi = document.getElementsByTagName("li"),
        oWidth = parseFloat(getComputedStyle(aLi[0]).width),
        oWrap = document.getElementsByClassName("wrap")[0],
        len = aLi.length,
        index = 0;
    function btnPre(){
        index--;
        if(index < 0){
            oUl.style.transition = 0 + "s";
            oUl.style.left = -oWidth*(len-1) + "px";
            index = len - 2;
            setTimeout(function(){
                oUl.style.transition = 1 + "s";
                oUl.style.left = -oWidth*(index) + "px";
            },1000/60);
        }
        else{
            oUl.style.transition = 1 + "s";
            oUl.style.left = -oWidth*(index) + "px";
        }
    }
    function btnNext(){
        index++;
        if(index === len-1){
        oUl.style.left = -oWidth*index + "px";
        index = 0;
        setTimeout(function(){
        oUl.style.transition = 0 + "s";
        oUl.style.left = 0 + "px";

        },1000);
        }
        else{
        oUl.style.transition = 1 + "s";
        oUl.style.left = -oWidth*index + "px";
        }
    }
    function throttle(fn,time){
        var startTime = new Date();
        return function(){
            var time_ = (new Date() - startTime) >= time;
            if(time_){
                fn.apply(this);
                startTime = new Date();
            }
        }
    }
    aButton[0].onclick = throttle(btnPre,1000);
    aButton[1].onclick = throttle(btnNext,1000);
    var timer = setInterval(btnNext,5000);
    oWrap.onmouseover = function(){
        clearInterval(timer);
    }
    oWrap.onmouseout = function(){
        timer = setInterval(btnNext,5000);
    }
})();

四、结语

写完这篇文章看下时间已经凌晨三点多了,也该去睡觉了,最后,感谢大家阅读~’

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页