JS 函数节流和防抖

目的

函数防抖和函数节流:优化高频率执行js代码的一种手段,js中的一些事件如浏览器的resize、scroll,鼠标的mousemove、mouseover,input输入框的keypress等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。为了优化体验,需要对这类事件进行调用次数的限制。
简而言之,目的都是,降低回调执行频率。节省计算资源。

函数防抖

高频事件触发,n秒后只执行一次,如果n秒内再次被触发,则重新计算时间。

实现代码

// ES6 可立即执行版本(封装完成未测试,应该好用)
/**
 * @param {fn}
 * @param {delay} 时间间隔ms
 * @param {isRun}  是否立即执行:true false
 * @return {*}
 */
function debounce(fn, delay=100, isRun=false){
  let timer = null;
  return function(){
    let args = arguments;
    if(timer){
      clearTimeout(timer)
    }else{
      isRun && fn.apply(this, args)
    }
    timer = setTimeout(()=>{
      timer = null;
      fn.apply(this, args)
    }, delay)
  }
}
// ES5  延时执行 版本
function debounce(fn, delay) {
    var timer; // 维护一个 timer
    return function () {
        var _this = this; // 取debounce执行作用域的this
        var args = arguments;
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(function () {
            fn.apply(_this, args); // 用apply指向调用debounce的对象,相当于_this.fn(args);
        }, delay);
    };
}
// ES6 延时执行 版本(已测试,好用!!!)
function debounce (fn, delay=100){
  let timer = null
  return function () {
    if(timer){
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments) // 箭头函数的 this 和 arguments 取的是定义时外层的函数的
      timer = null
    }, delay);
  }
}

测试用例

function testDebounce(e, content) {
    console.log(e, content);
}
var testDebounceFn = debounce(testDebounce, 1000); // 防抖函数
document.onmousemove = function (e) {
    testDebounceFn(e, 'debounce'); // 给防抖函数传参
}

函数节流

高频事件触发,n秒内只会执行一次。

实现代码

/**
 * 函数节流  ES6 可立即执行版本(已测试,好用!!!)
 * @param {Function} fn
 * @param {number} delay 时间间隔ms
 * @param {boolean} isRun  是否立即执行, 默认true
 * @return {Function}
 */
function throttle(fn, delay=100, isRun=true){
  let timer = null;
  return function(){
    let args = arguments;
    if(!timer){
      isRun && fn.apply(this, args)
      timer = setTimeout(()=>{
        timer = null;
        isRun || fn.apply(this, args)
      }, delay)
    }
  }
}
// ES5 延时执行 版本
function throttle(fn, delay) {
    var timer;
    return function () {
        var _this = this;
        var args = arguments;
        if (timer) {
            return;
        }
        timer = setTimeout(function () {
            fn.apply(_this, args);
            timer = null; // 在delay后执行完fn之后清空timer,此时timer为假,throttle触发可以进入计时器
        }, delay)
    }
}
// ES6 延时执行 版本(已测试,好用!!!)
function throttle(fn, delay=100){
  let timer
  return function() {
    if(timer) {
      return
    }
    timer = setTimeout(()=> {
      fn.apply(this, arguments)
      timer = null
    }, delay)
  }
}

测试用例

function testThrottle(e, content) {
    console.log(e, content);
}
var testThrottleFn = throttle(testThrottle, 1000); // 节流函数
document.onmousemove = function (e) {
    testThrottleFn(e, 'throttle'); // 给节流函数传参
}

补充:工具函数在Vue中的使用

methods: {
    handleSearch(value) {...},
    debounceHandleSearch: debounce(function(){this.handleSearch(...arguments)}, 1000),
	// 因为在运行阶段,debounce函数中 `this` 的指向不是Vue实例,因此获取不到 `handleSearch`,所以在编写阶段“待执行函数”用一层函数包装后,立即执行,从而敲定该函数的运行环境。
}

常见应用场景

函数防抖的应用场景

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求。
  • 手机号、邮箱验证输入检测。
  • 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

函数节流的应用场景

  • 滚动加载,加载更多或滚到底部监听
  • 拖拽一个元素,要随时获取被拖拽元素的位置
  • 高频点击提交,表单重复提交

参考:[https://segmentfault.com/a/1190000018445196]

posted @ 2021-03-08 11:11  Better-HTQ  阅读(109)  评论(0编辑  收藏  举报