美文网首页
前端性能优化(二)——函数节流

前端性能优化(二)——函数节流

作者: 任无名F | 来源:发表于2017-05-08 15:46 被阅读0次

web开发中经常遇到这样的场景,监听一个事件,然后进行相应的DOM操作。但是,当所监听的事件触发频率非常高的时候,会因为DOM的频繁操作导致浏览器卡顿甚至卡死,类似的事件如下:

  1. window对象的resize、scroll
  2. 拖拽时的mouseover
  3. 射击游戏的mousedown、keydown
  4. 文字输入自动补全时的keyup事件

以上的情况解决方案又分为两类,第一类就是window的resize事件,第二类是其他所有情况。两种解决方案分别是debounce和throttle。

debounce

当你用手按住弹簧的时候,它不会弹起直到你松开手。
也就是说,函数会在事件触发N毫秒后被调用,但前提是你已经“松开了手”,如果在N毫秒内事件再次被触发,会清空之前的计时器重新计时。

function debounce(idle, action) {
  let timer, args = [].slice.call(arguments, 2);
  return function() {
    let ctx = this, total_args = args.concat([].slice.call(arguments)); // 参数柯里化
    clearTimeout(timer); // 事件被触发就清空计时器
    timer = setTimeout(function() {
      action.apply(ctx, total_args);
    }, idle);
  }
}

function action() {
  ......
}
let doAction = debounce(100, action, arg0, arg1);
window.onresize = function() {
  doAction(arg2, arg3); // 此处参数可以分批次传入
}
throttle

平时,水龙头的水是不间断的流出的,你可以将水龙头拧紧直到水一滴一滴的流出。
也就是设定一个周期,函数触发的周期不会小于这个周期。

function throttle1(idle, action) {
  let flag = true, timer;
  let args = [].slice.call(arguments, 2);
  return function() {
    let ctx = this, total_args = args.concat([].slice.call(arguments));
    if(flag) { // flag为true时才开始计时器
      flag = false; // 开始计时器后,flag置为false,直到动作执行完
      timer = setTimeout(function() {
        action.apply(ctx, total_args);
        flag = true; // 进行一次动作后,将flag置为true,再进行下一次动作
      }, idle);
    }
  }
}

function throttle2(idle, action) {
  let last = 0;
  let args = [].slice.call(arguments, 2);
  return function() {
    let ctx = this, cur = +new Date();
    let total_args = args.concat([].slice.call(arguments));
    if(cur - last > idle) { // 周期大于idle时,才会进行动作
      action.apply(ctx, total_args);
      last = cur; // 重新计算周期
    }
  }
}

function action() {
  ......
}
let doAction = throttle1(100, action, arg0, arg1);
window.onscroll = function() {
  doAction(arg2, arg3); // 此处参数可以分批次传入
}

相关文章

网友评论

      本文标题:前端性能优化(二)——函数节流

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