性能优化之节流、防抖

1. 防抖:

  • 由于dom操作极其昂贵,所以尝试过多的dom操作有可能会将浏览器搞崩溃,比如onresize、onscroll这类事件操作;
  • 为了解决这个问题,引出防抖的概念(某些代码不可以在没有间断的情况下连续重复执行);
  • 方案:第一次调用函数创建一个定时器,在指定时间之后执行代码;在第二次调用时,清除掉前一次的定时器并重新设置一个;
  • 这种方案下,如果第一个定时器已经执行,这个操作就没意义;如果第一个没执行,则将其替换为新的定时器;目的是只有在执行函数的请求停止一段时间后才执行;
  • 适用于代码是周期执行的,但是你不能控制请求执行的速率;
  • 函数防抖让一个函数只有在你不断触发后停下来歇会才开始执行,中间你操作得太快它直接无视。
    // 函数防抖
    function debounce(method, context) {
        clearTimeout(method.tid);  // mthod是真实要执行的函数,context是执行的作用域(默认window)
        method.tid = setTimeout(function() {
            method.call(context)   // 确保方法在适当的环境中执行
        }, 100);
    }
    
    // onscroll时函数防抖
    function scrollFun() {
        var marginBot = 0;
        if (document.documentElement) {
            marginBot = document.documentElement.scrollHeight - (document.documentElement.scrollTop+document.body.scrollTop) - document.documentElement.clientHeight;
        } else {
            marginBot = document.body.scrollHeight - document.body.scrollTop - document.body.clientHeight;
        }
        if(marginBot <= 0) {
            // 滚动到底部加载数据操作
        }
    }
    window.onscroll = function() {
        debounce(scrollFun);
    }

2. 节流

  • 如果我们不希望每次都是要事件结束后等待延迟时间后执行回调;
  • 我们可以先给定一个时间段duration,过了这个时间段以后我们执行相应的操作;如果没有过这个时间段,那么就按照函数节流的思路,开关定时器就ok。

function throttle(method, delay, duration){
    var timer = null, stime = new Date();          // 记录下开始执行函数的时间
    return function() {
        var context = this, args = arguments,
        ctime = new Date();   // 记录下当前时间
        
        clearTimeout(timer);     // 函数节流里的思路

        // 记录下的两个时间相减再与duration进行比较
        if (ctime - stime >= duration) {
            method.apply(context, args);
            stime = ctime;
        }
    }
}

window.onresize = throttle(method, 50, 100);
// 50ms的间隔内连续触发的调用,后一个调用会把前一个调用的等待处理掉,但每隔100ms至少执行一次

3. 滚动实例区分下:

    normal:滚动会立即触发事件执行;

    throttle: 延迟100ms直到100ms以内没有事件触发之后执行,这样如果一直在操作,有可能一直不会触发事件发生;

    debounce:50ms的间隔内连续触发的调用,后一个调用会把前一个调用的等待处理掉,但每隔100ms至少执行一次。

4. 滚动到目标节点:

  • 获取目标节点偏移量var len = $('target').offset().top或document.querySelector('target').offsetTop;
  • 滚动$('body').animate(scrollTop: len)或document.querySelector('body').scrollTop = len;
原文地址:https://www.cnblogs.com/colima/p/7163057.html