什么是防抖以及为什么它很重要

防抖是一种编程模式,用于确保耗时任务不会过于频繁地触发,从而防止性能问题或服务器被请求淹没。这在搜索输入等场景中特别有用,您可能不希望每次按键都触发搜索请求,而是在用户停止输入后才触发。

通过实现防抖,您可以增强用户体验和应用程序效率。这是通过延迟函数执行来实现的,直到其上次调用后经过指定的时间量。

何时使用防抖

防抖最适合用于您希望限制函数调用频率的情况。常见的用例包括

  • 用户输入验证:延迟验证,直到用户停止输入,以避免对每次按键进行不必要的处理。
  • 搜索功能:等待用户完成输入搜索查询,然后再开始搜索过程,减少发送到服务器的搜索请求数量。
  • 窗口调整大小:限制浏览器窗口调整大小时重新计算或调整的次数。

如何在 Qwik 中实现防抖

Qwik 框架提供了独特的管理状态和效果的功能,这种方式既可序列化又高效。在 Qwik 中实现防抖涉及使用 Qwik 的基本元素,例如 useSignal 用于状态管理,以及 $ 用于标记可以捕获状态而不会破坏序列化的函数。下面是一个简单的防抖模式。它的行为类似于基于闭包的防抖,在超时到达时执行函数。

export const useDebouncer = (fn: QRL<(args: any) => void>, delay: number) => {
  const timeoutId = useSignal<number>();
 
  return $((args: any) => {
    clearTimeout(timeoutId.value);
    timeoutId.value = Number(setTimeout(() => fn(args), delay));
  });
};

此防抖接受一个函数和一个延迟作为参数。它利用 useSignal 来跟踪 timeoutID,确保与 Qwik 的可恢复模型及其对 QRL 的使用兼容。返回的函数在被调用时,会清除任何现有的超时,并设置一个新的超时,以便在指定的延迟后调用提供的函数。

如何使用防抖

以下示例演示了在组件中使用防抖来有效地管理用户输入。通过对输入进行防抖,应用程序仅在用户停止输入 1 秒后才更新状态,从而优化了 API 调用或数据过滤等操作的性能。

import { $, useSignal, component$, type QRL } from "@builder.io/qwik";
import { useDebouncer } from "~/utils/debouncer";
 
export default component$(() => {
  const debouncedValue = useSignal("");
 
  const debounce = useDebouncer(
    $((value: string) => {
      debouncedValue.value = value;
    }),
    1000
  );
 
  return (
    <>
      <input
        onInput$={(_, target) => {
          debounce(target.value);
        }}
      />
      <p>{debouncedValue.value}</p>
    </>
  );
});

实时演示

在下面的实时演示中,useDebouncer 用于在上次按键后经过 1 秒延迟后更新 debouncedValue 信号。

额外:useDebouncer$

为了为我们的开发者节省额外的“用 $() 包装”操作。

我们可以利用 Qwik 的 implicit$FirstArg 函数来创建一个 useDebouncer$ 函数,该函数会自动用 $() 包装提供的函数。

这就是 Qwik 实际实现所有内置 $ 钩子的方式。

export const useDebouncerQrl = (fn: QRL<(args: any) => void>, delay: number) => {
  const timeoutId = useSignal<number>();
 
  return $((args: any) => {
    clearTimeout(timeoutId.value);
    timeoutId.value = Number(setTimeout(() => fn(args), delay));
  });
};
 
export const useDebouncer$ = implicit$FirstArg(useDebouncerQrl);

现在我们可以这样做

const debounce = useDebouncer$(
  (value: string) => {
    debouncedValue.value = value;
  },
  1000
);

很棒,对吧? :)

贡献者

感谢所有帮助改进此文档的贡献者!

  • n8sabes
  • KenAKAFrosty
  • shairez