事件处理:节流与防抖

通常为了避免频繁的事件操作,引起浏览器的太多的重绘与回流,造成浏览器的崩溃或者掉帧。通常会通过防抖与节流的方式来优化用户体验
防抖(debounce):触发事件后,就是把触发非常频繁的事件合并成一次去执行。即在指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函数的执行时间会基于此刻重新开始计算。
通常会通过setTimeout进行实现

var debounce = function(fn, delayTime) {
var timeId; 
return function() {  
var context = this, args = arguments;
    timeId && clearTimeout(timeId);
    timeId = setTimeout(function{
      fn.apply(context, args);//使用apply改变传入的fn方法中的this指向,指向绑定事件的DOM元素。
    }, delayTime)
  }
}

执行debounce函数之后会返回一个新的函数,通过闭包的形式,维护一个变量timeId,每次执行该函数的时候会结束之前的延迟操作,重新执行setTimeout方法,也就实现了上面所说的指定的时间内多次触发同一个事件,会合并执行一次。
节流(throttle):繁触发事件时,只会在指定的时间段内执行事件回调,即触发事件间隔大于等于指定的时间才会执行回调函数
实现方式:时间戳和setTimeout定时器
时间戳的方式:通过比较两次时间戳的间隔是否大于等于事先指定的时间则执行事件回调。

var  throttle = (fn, delayTime) => {
var  _start = Date.now();
return function() {
var  _now = Date.now(), context = this, args = arguments;  
if (_now - _start >= delayTime) {
      fn.apply(context, args);
      _start = Date.now();
    }
  }
}

定时器:设置了一个标志变量flag,当delayTime之后执行事件回调,便会把这个变量重置,表示一次回调已经执行结束

var  throttle = (fn, delayTime) => {
var  flag;
return function() {
var context = this, args = arguments;  
if  (!flag) {
      flag = setTimeout(function () {
        fn.apply(context, args);
        flag = false;
      }, delayTime);
    }
  }
}

1、使用时间戳方式,页面加载的时候就会开始计时,如果页面加载时间大于我们设定的delayTime,第一次触发事件回调的时候便会立即fn,并不会延迟。如果最后一次触发回调与前一次触发回调的时间差小于delayTime,则最后一次触发事件并不会执行fn;
2、使用定时器方式,我们第一次触发回调的时候才会开始计时,如果最后一次触发回调事件与前一次时间间隔小于delayTime,delayTime之后仍会执行fn。
频繁触发事件时,函数防抖只会在最后一次触发事件只会才会执行回调内容,其他情况下会重新计算延迟事件,而函数节流便会很有规律的每隔一定时间执行一次回调函数。

防抖和节流只是减少了事件回调函数的执行次数,并不会减少事件的触发频率。
防抖和节流并没有从本质上解决性能问题,我们还应该注意优化我们事件回调函数的逻辑功能,避免在回调中执行比较复杂的DOM操作,减少浏览器reflow和repaint。

常用的节流与防抖的工具库,
事件处理:节流与防抖