1

前言

目前在做一个大型的前端后台管理系统,里面有大量的表单校验和输入框查询操作。如果每次用户输入的瞬间都去响应或者检测,其实是不太必要的,因为用户的输入一般具有连续性,所以可以在用户输入产生停顿的时候再去校验或者向服务器发送请求。

解决方案

采用的解决方案是直接使用 lodash 防抖函数 _.debouce
详情可以参照: lodash 中文文档

理解防抖

作用:延迟执行,防止间隔时间内连续调用,减少响应次数,优化性能。
自实现代码:

  /**
   *
   * @param  {function}   func      回调函数
   * @param  {number}     wait      表示时间窗口的间隔
   * @param  {boolean}    immediate 是否立即执行 
   *                               
   * @return {function}             返回调用函数
   */
        var debounce = (func, wait = 100, immediate = false) => {
            let timer, ctx, args;

            // 延迟执行函数
            const later = () => setTimeout(() => {
                timer = null;
                if (!immediate) {
                    func.call(ctx, ...args);
                    ctx = args = null;
                }
            }, wait);

            return function() {
                if (!timer) {
                    timer = later();
                    if (immediate) {
                        func.call(this, ...arguments);
                    } else {
                        ctx = this;
                        args = arguments;
                    }
                } else {
                    clearTimeout(timer);
                    timer = later();
                }
            }
        }

如果是立即执行(immediate: true)

  • 第一次调用,创建一个保护性质的 timer
  • 立即执行传入的 func 并且将返回函数的执行上下文绑定到 func
  • 如果达到 wait 时间执行定时器函数,timer 置为 null,等待一个新的调用过程
  • 如果没有达到 wait 时间再次调用
  • 此时 timer 仍然存在,于是会调用 clearTimeout 清除原有定时器,再创建一个新的 timer
  • 达到了 wait 时间内无法连续调用的情况,这就是为什么说第一次调用创建的timer是一个保护性质的

如果延迟执行(immediate: false)

  • 第一次调用,创建一个 timer
  • 缓存执行上下文 thisarguments
  • 由于 JS 中的异步机制,就算 wait 值为 0timer 中的函数也会晚于上一步执行
  • 如果达到 wait 事件执行定时器函数,拿到的是正确的 thisargs,而非 undefined
  • 执行完毕后清除当前缓存执行上下文和参数,等待一个新的调用过程
  • 如果没有达到 wait 时间再次调用
  • 此时 timer 仍然存在,于是会调用 clearTimeout 清除原有定时器,再创建一个新的 timer
  • 达到了在 wait 时间内无法连续调用的结果

烂笔头
108 声望1 粉丝

笑着摸摸头,一根都不留...