js之防抖与节流

2018-09-25  本文已影响18人  隐号骑士

防抖和节流是: 优化高频率执行代码的手段
目的: 节约浏览器(服务器)性能
方式: 减少函数执行次数

防抖

上电梯的例子: 电梯总是在进出人(监听事件)之后的5秒关门(执行方法), 如果5秒钟之内又有人进出, 则重新开始计时, 直到最后一个进出电梯的事件发生5秒钟之后执行关门.

思路: 设置定时器延迟执行事件 , 一旦在延迟的过程中触发了新的监听事件 , 则销毁并重新设置定时器 .

function Debounce(func, wait) {
  var timeout;
  return function () {
    clearTimeout(timeout)
    timeout = setTimeout(function () { func() }, wait)
  }
}

改善后的版本(绑定监听事件时的this,传递arguments)

function Debounce(func, wait) {
  var timeout;
  var arg = [];
  for (var i = 2; i < arguments.length; i++) {
    arg.push(arguments[i]);//传递arguments
  }
  return function () {
    var context = this;//传递this
    clearTimeout(timeout)
    timeout = setTimeout(function () { func.apply(context, arg) }, wait)
  }
}

节流

播放电影的例子: 人眼的识别效率是最高每秒24次, 所以电影播放的速度是每秒24帧, 大于这个帧数其实也是一种浪费. 如果片源(监听事件)是每秒100帧, 可以进行一些处理, 让它以每秒24帧的最大执行速率播放(执行方法).

思路 : 设置一个标识符表示当前时间是否可以执行回调函数 , 触发监听事件时根据该变量判断是否执行方法 , 执行方法时更新此变量 .

//时间戳版本
function Throttle(fn, wait) {
  var lastTime = null;//设置标识符
  var arg = [];
  for (var i = 2; i < arguments.length; i++) {
    arg.push(arguments[i]);//传递arguments
  }
  return function () {
    var execTime = + new Date()
    if (execTime - lastTime > wait || !lastTime) {
      fn.apply(this, arg);
      lastTime = execTime
    }
  }
}
//定时器版本
function Throttle(fn, wait) {
  var canRun = true;//设置标识符
  var arg = [];
  for (var i = 2; i < arguments.length; i++) {
    arg.push(arguments[i]);//传递arguments
  }
  return function () {
    if (!canRun) {
      return;// 判断是否已空闲,如果在执行中,则直接return
    }
    var context = this;//传递this
    canRun = false;
    setTimeout(function () {
      fn.apply(context, arg);
      canRun = true;
    }, wait);
  }
}

使用时 , 可以自己封装简单的防抖与节流函数 , 也可以使用第三方方法库 .
underscore.js
lodash.js

requestAnimationFrame

requestAnimationFrame是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘。(告诉浏览器在下一个动画帧对页面进行重绘).

function execWithRequestAnimationFrame(fn) {
  var scheduledAnimationFrame = false;
  var arg = [];
  for (var i = 1; i < arguments.length; i++) {
    arg.push(arguments[i]);//传递arguments
  }
  return function () {
    if (scheduledAnimationFrame) {
       return;
    }
    scheduledAnimationFrame = true;
    var context = this;//传递this
    window.requestAnimationFrame(() => {
      scheduledAnimationFrame = false;
      fn.apply(context, arg);
    })
  }
}

不支持IE9及以下
可配合cancelAnimationFrame使用

上一篇下一篇

猜你喜欢

热点阅读