性能优化之节流、防抖
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;