怎么使用debounce(防抖)处理实时搜索

6 阅读5分钟

怎么使用debounce(防抖)处理实时搜索

防抖(Debounce)是一种常用的性能优化技术,特别适用于像实时搜索这类频繁触发事件的场景。它的核心思想是在事件被触发后,延迟一定时间再执行回调函数,如果在延迟时间内该事件又被触发了,就重新计时,直到延迟时间内没有新的事件触发,才执行回调函数。下面以原生 JavaScript 和 Vue.js 为例,介绍如何使用防抖处理实时搜索:

原生 JavaScript 中使用防抖处理实时搜索

html

预览

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Debounce Search</title>
</head>

<body>
  <input type="text" id="searchInput" placeholder="输入关键词进行搜索">
  <script>
    // 模拟数据数组
    const data = [
      { id: 1, cnname: "张三", enname: "Zhang San" },
      { id: 2, cnname: "李四", enname: "Li Si" },
      { id: 3, cnname: "王小明", enname: "Wang Xiaoming" },
      { id: 4, cnname: "阿里巴巴", enname: "Alibaba" },
      { id: 5, cnname: "腾讯科技", enname: "Tencent" }
    ];

    // 防抖函数实现
    function debounce(func, delay) {
      let timer;
      return function () {
        const context = this;
        const args = arguments;
        clearTimeout(timer);
        timer = setTimeout(() => {
          func.apply(context, args);
        }, delay);
      };
    }

    // 模糊搜索函数
    function fuzzySearch(array, keyword) {
      if (!keyword) return array;
      const lowerKeyword = keyword.toLowerCase();
      return array.filter(item => {
        return (item.cnname && item.cnname.toLowerCase().includes(lowerKeyword)) ||
          (item.enname && item.enname.toLowerCase().includes(lowerKeyword));
      });
    }

    // 获取搜索输入框元素
    const searchInput = document.getElementById('searchInput');
    // 使用防抖函数包装搜索函数
    const debouncedSearch = debounce(() => {
      const keyword = searchInput.value;
      const result = fuzzySearch(data, keyword);
      console.log("搜索结果:", result);
    }, 300); // 延迟300毫秒执行搜索

    // 监听输入框的input事件
    searchInput.addEventListener('input', debouncedSearch);
  </script>
</body>

</html>

在上述代码中:

  1. debounce函数接收要延迟执行的函数func和延迟时间delay作为参数,返回一个新的函数。这个新函数在每次被调用时,会清除之前设置的定时器(如果存在),并重新设置一个新的定时器,在延迟时间到达后执行func
  2. fuzzySearch是模糊搜索函数,用于根据关键词对数据数组进行过滤。
  3. 通过addEventListener监听输入框的input事件,并将debouncedSearch函数作为回调,这样在用户快速输入时,搜索函数不会频繁执行,而是在用户停止输入 300 毫秒后才执行。

在 Vue.js 中使用防抖处理实时搜索

vue

<template>
  <div>
    <h3>使用防抖的实时搜索</h3>
    <input
      type="text"
      v-model="keyword"
      placeholder="输入中文或英文关键词..."
      class="search-input"
    >
    <div class="result-list">
      <div v-for="item in filteredData" :key="item.id" class="result-item">
        <span>ID: {{ item.id }}</span>
        <span>中文名称: {{ item.cnname }}</span>
        <span>英文名称: {{ item.enname }}</span>
      </div>
    </div>
  </div>
</template>

<script>
// 防抖函数
export function debounce(func, delay) {
  let timer;
  return function () {
    const context = this;
    const args = arguments;
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(context, args);
    }, delay);
  };
}

export default {
  data() {
    return {
      keyword: '',
      originalData: [
        { id: 1, cnname: "张三", enname: "Zhang San" },
        // ... 同上数据 ...
      ],
      filteredData: []
    };
  },
  mounted() {
    // 使用防抖函数包装搜索方法
    this.debouncedSearch = debounce(this.searchData, 300);
    // 监听keyword变化,触发防抖后的搜索
    this.$watch('keyword', this.debouncedSearch);
  },
  methods: {
    searchData() {
      if (!this.keyword) {
        this.filteredData = this.originalData;
        return;
      }
      const lowerKeyword = this.keyword.toLowerCase();
      this.filteredData = this.originalData.filter(item => {
        return (item.cnname && item.cnname.toLowerCase().includes(lowerKeyword)) ||
          (item.enname && item.enname.toLowerCase().includes(lowerKeyword));
      });
    }
  }
};
</script>

<style>
.search-input {
  padding: 8px;
  width: 300px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
.result-list {
  margin-top: 15px;
}
.result-item {
  padding: 8px;
  border-bottom: 1px solid #f0f0f0;
}
</style>

在 Vue 项目中:

  1. 定义了debounce函数,原理和原生 JavaScript 中的防抖函数一致。

  2. mounted生命周期钩子中,使用防抖函数包装searchData方法,并通过$watch监听keyword的变化,触发防抖后的搜索操作。这样在用户输入过程中,搜索方法不会频繁执行,从而提升性能。

通过以上两种方式,都能有效利用防抖技术来优化实时搜索功能,减少不必要的函数调用,提升应用的性能和用户体验。

Lodash 中的防抖怎么使用

Lodash 提供了强大的 debounce 函数,相比手动实现更加健壮且功能丰富(如支持立即执行、取消、flush 等)。以下是它的详细用法:

1. 基础用法:延迟执行搜索

javascript

import { debounce } from 'lodash';

// 模拟搜索函数(实际项目中可能是API请求)
function search(keyword) {
  console.log('执行搜索:', keyword);
  // 返回搜索结果...
}

// 创建防抖版本的搜索函数,延迟300ms
const debouncedSearch = debounce(search, 300);

// 绑定到输入事件
document.getElementById('searchInput').addEventListener('input', (e) => {
  debouncedSearch(e.target.value);
});
  • 效果:用户输入时,只有停止输入 300ms 后 才会执行 search 函数。

2. 常用配置选项

2.1 leading:是否立即执行

javascript

// 立即执行首次调用,之后的调用需等待300ms冷却期
const debouncedSearch = debounce(search, 300, {
  leading: true,  // 首次立即执行
  trailing: true  // 最后一次也执行(默认值)
});
  • 场景:适合需要立即反馈的场景(如搜索建议),同时避免连续触发。
2.2 maxWait:最长等待时间

javascript

// 最长等待500ms,即使持续输入也会每500ms执行一次
const debouncedSearch = debounce(search, 300, {
  maxWait: 500
});
  • 场景:适合需要定期更新结果的场景(如自动保存)。

3. 取消与立即执行

3.1 cancel():取消待执行的函数

javascript

// 取消未执行的搜索(如用户离开页面时)
debouncedSearch.cancel();
3.2 flush():立即执行待执行的函数

javascript

// 立即执行并获取结果(如用户点击搜索按钮时)
debouncedSearch.flush();

4. 在 Vue.js 中的完整示例

vue

<template>
  <div>
    <input 
      v-model="keyword" 
      @input="handleInput" 
      placeholder="输入关键词..." 
    >
    <button @click="flushSearch">立即搜索</button>
  </div>
</template>

<script>
import { debounce } from 'lodash';

export default {
  data() {
    return {
      keyword: '',
      debouncedSearch: null
    };
  },
  created() {
    // 创建防抖函数
    this.debouncedSearch = debounce(this.fetchResults, 300);
  },
  methods: {
    // 实际执行搜索的方法
    fetchResults() {
      console.log('API请求:', this.keyword);
      // 调用API获取搜索结果...
    },
    // 处理输入事件
    handleInput() {
      this.debouncedSearch();
    },
    // 立即执行搜索
    flushSearch() {
      this.debouncedSearch.flush();
    }
  },
  beforeDestroy() {
    // 组件销毁前取消未执行的请求
    this.debouncedSearch.cancel();
  }
};
</script>

5. 与原生防抖的区别

特性原生实现Lodash debounce
立即执行(leading)需手动实现✅ 内置支持
最长等待时间(maxWait)不支持✅ 防止长时间不执行
取消 / 立即执行需手动管理定时器✅ cancel()/flush()
函数参数传递需要手动处理上下文✅ 自动保留参数

注意事项

  1. 安装依赖

    bash

    npm install lodash
    
  2. 按需导入

    javascript

    // 推荐:只导入debounce函数,减少打包体积
    import debounce from 'lodash/debounce';
    
  3. 性能考量

    • 防抖延迟时间不宜过短(如 <50ms),否则可能失去优化意义。
    • 对于高频触发的场景(如滚动、窗口调整),建议使用 节流(throttle)

通过 Lodash 的 debounce,你可以更优雅地处理实时搜索、自动保存等高频触发场景,同时避免手动管理定时器的复杂性。