美文网首页
JavaScript 函数节流

JavaScript 函数节流

作者: HelloJames | 来源:发表于2019-01-01 19:46 被阅读12次
    • throttle
    • debounce

    为什么要函数节流

    在下列场景中, 事件会被频繁触发, 从而导致频繁的执行DOM执行或资源加载, 导致UI停顿甚至浏览器崩溃。

    • Window对象的resize、scroll事件
    • 拖拽时元素时的mousemove事件
    • 按键的mousedown、keydown、keyup事件
    • 元素的onclick事件(加载资源)

    例如, 以scroll事件进行解释:

    window.onscroll = function(){
        lazyload();
    };
    function lazyload(){
        console.log("scroll执行了"+scrollnum);
    }
    

    本意只是想让鼠标滚动一次执行一次滚动函数, 但是window的onscroll函数并不是等 scroll结束之才会调用, 鼠标滚动或拖动滚动条, 就会不停的触发scroll事件, 如果处理的东西多, 低版本的IE也会陷入假死状态。

    解决办法

    debounce

    当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间。这种比较适合window的resize事件,实际需求大多为停止改变大小n毫秒后执行后续处理;

    去抖1
    window.onscroll = function(){
      debounce(lazyload,window);
    };
    function debounce(method,context){
            clearTimeout(method.timeout);
            method.timeout = setTimeout(function(){
            method.call(context);
        },500);
    }
    function lazyload(){
        console.log("scroll执行了"+scrollnum);
    }
    

    利用定时器, 让函数执行延迟500毫秒, 在500毫秒内如果有函数又被调用则删除上一次调用, 这次调用500毫秒后执行, 如此反复。

    去抖2

    另一种节流方式, 是通过返回闭包的形式, 可以设置延迟时间, 两者运行的结果是一样, 但是在实际操作时设置延迟500毫秒时, 滚动过了一会儿才执行, 设置为delay为100的时候在视觉上就没有感觉延迟, 而且函数也只滚动了一次。

    function debounce1(method,delay){
        var timer = null;
        return function(){
            var context = this, args = arguments;
            clearTimeout(timer);
            timer = setTimeout(function(){
                 method.apply(context,args);
             },delay);
        }
    }
    

    throttle

    在上例代码中, 当鼠标一直滚动时, lazyload函数会被不断的延迟, 只有当鼠标停下来时才会被执行。

    但这在有些需要及时显示的情况下, 就显得不那么友好了(对于实现keyup事件的提示也没有意义了), 所以可以为函数添加一个参数作为固定间隔, 到了这个时间间隔就必须执行, 这个时候就引入了节流:

    节流: 如果将水龙头拧紧直到水是以水滴的形式流出, 此时会发现每隔一段时间, 就会有一滴水流出, 也就是说会预先设定一个执行周期, 当调用动作的时刻大于等于执行周期则执行该动作, 然后进入下一个新周期。
    代码如下:

    function throttle2(method, delay, time) {
          var timeout,startTime = new Date();
          return function() {
                var context = this, args = arguments,
                var curTime = new Date();
                clearTimeout(timeout);
                // 若达到了触发的时间间隔,则立即触发handler
                if (curTime - startTime >= time) {
                        method.apply(context, args);
                        startTime = curTime;
                 // 若没有达到触发的时间间隔,则重新设定定时器
                } else {
                    timeout = setTimeout(method, delay);
                }
    };
    

    在这个函数中, 当一次时间较长的时候还是会执行两次, 而不是等滚动停止之后再执行。 达到了想要的效果, 既没有频繁的执行也没有最后执行。

    相关文章

      网友评论

          本文标题:JavaScript 函数节流

          本文链接:https://www.haomeiwen.com/subject/jhyfqftx.html