Debounce和Throttling是什么?何时使用它们?


性能是现代Web应用程序中最关键的方面之一。作为开发者,我们遵循各种技术来提升应用程序的性能,以提供更好的用户体验。例如,防抖和节流是两种简单而强大的技术,我们可以在JavaScript应用程序中使用以改善性能。

为什么我们需要使用防抖和节流?

通常,开发者可以自由决定何时调用一个函数。但有时,他们必须将控制权交给用户。例如,在应用程序中广泛使用事件触发器来根据事件(如按键、按钮点击和鼠标移动)触发函数。在这种情况下,用户可能会触发这些事件远远超过所需次数,导致应用程序的性能问题。

例如,您可能有一个搜索栏,随着用户输入,从后端获取建议的功能,或者一个调整页面布局的resize事件处理器。在这些情况下,您不希望代码执行得太频繁,因为这可能导致不必要的网络请求、界面卡顿或高CPU使用率。

为了解决这个问题,您可以使用称为“防抖”(Debouncing)和“节流”(Throttling)的两种技术。这些技术允许您控制代码执行的频率,减少其被调用的次数。

什么是防抖(Debouncing)?

防抖是一种技术,它延迟函数执行直到用户停止执行某个动作达到指定的时间间隔为止。例如,如果您有一个搜索栏,在用户输入时从后端获取建议,您可以对执行API调用的函数进行防抖处理,以便只在用户停止输入几秒钟后才运行该函数。这样,您可以避免进行过多可能使服务器超载或返回无关结果的API调用。

JavaScript中实现防抖,您可以使用一个计时器变量来跟踪延迟时间。您可以使用setTimeout函数设置一个定时器,在延迟时间后执行您的函数。您还可以使用clearTimeout函数在延迟时间结束前取消定时器,以确保函数只在用户停止执行动作后运行一次。

以下是JavaScript中实现防抖的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 一个使用搜索查询进行API调用的函数
function searchHandler(query) {
// 使用搜索查询进行API调用
getSearchResults(query);
}

// 防抖函数,接受一个函数和延迟时间作为参数
function debounce(func, delay) {
// 用于跟踪延迟时间的计时器变量
let timer;
// 返回一个函数,接受参数
return function(...args) {
// 清除之前的计时器(如果有)
clearTimeout(timer);
// 设置一个新的计时器,在延迟时间后执行函数
timer = setTimeout(() => {
// 应用带有参数的函数
func.apply(this, args);
}, delay);
};
}

// 使用500ms延迟的防抖搜索处理器
const debouncedSearchHandler = debounce(searchHandler, 500);

// 给搜索栏输入添加事件监听器
searchBar.addEventListener("input", (event) => {
// 获取输入的值
const query = event.target.value;
// 使用查询调用防抖的搜索处理器
debouncedSearchHandler(query);
});

在这个示例中,我们有一个searchHandler函数,它使用搜索查询进行API调用。我们还有一个debounce函数,它接受一个函数和一个延迟时间作为参数,并返回该函数的防抖控制。我们使用这个debounce函数创建了一个延迟500毫秒的debouncedSearchHandler函数。然后,我们给搜索栏输入添加了一个事件监听器,并使用输入的值调用debouncedSearchHandler函数。这样,我们可以确保在用户停止输入500毫秒后只进行一次API调用。

什么是节流(Throttling)?

节流是一种技术,它限制函数在指定时间间隔内执行一次。例如,如果您有一个调整页面布局的resize事件处理器,您可以对更新布局的函数进行节流处理,以便它每100毫秒只运行一次。这样,您可以避免代码执行过于频繁,从而导致用户界面不流畅或高CPU使用率。

JavaScript中实现节流,您可以使用一个标志变量来跟踪函数当前是否正在运行。您可以使用setTimeout函数设置一个定时器,在时间间隔结束后重置该标志。您还可以使用if语句在执行函数之前检查标志变量是否为true。这样,您可以确保函数在每个时间间隔内只运行一次。

以下是JavaScript中实现节流的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 一个更新页面布局的函数
function updateLayout() {
// 更新布局逻辑
}

// 节流函数,接受一个函数和一个时间间隔作为参数
function throttle(func, interval) {
// 用于跟踪函数当前是否正在运行的标志变量
let isRunning = false;

// 返回一个函数,接受参数
return function(...args) {
// 如果函数当前没有在运行
if (!isRunning) {
// 将标志设置为true,表示函数开始运行
isRunning = true;

// 执行函数,带上参数
func.apply(this, args);

// 设置一个定时器,在时间间隔后重置标志为false
setTimeout(() => {
// 将标志设置为false,表示函数执行结束
isRunning = false;
}, interval);
}
};
}

// 使用100ms时间间隔的节流更新布局函数
const throttledUpdateLayout = throttle(updateLayout, 100);

// 给窗口resize事件添加事件监听器
window.addEventListener("resize", () => {
// 调用节流后的更新布局函数
throttledUpdateLayout();
});

在这个示例中,我们有一个updateLayout函数,它用于更新页面的布局。我们还有一个throttle函数,它接受一个函数和一个时间间隔作为参数,并返回该函数的节流版本。我们使用throttle函数创建了一个节流后的更新布局函数throttledUpdateLayout,时间间隔为100毫秒。然后,我们给窗口resize事件添加了一个事件监听器,并调用throttledUpdateLayout函数。这样,我们可以确保页面布局每100毫秒更新一次。

防抖(Debouncing)和节流(Throttling)之间的主要区别

  • 防抖(Debounce)通过监控用户动作之间的时间延迟,在延迟超过开发者定义的时间间隔时才执行回调函数。因此,如果使用防抖,连续的用户动作可能会显著延迟回调函数的执行。
  • 节流(Throttle)利用时间间隔以固定的间隔执行回调函数,直到事件触发结束。因此,不像防抖那样会让回调函数的执行延迟较长时间。

防抖和节流都是改善代码性能的有用技术,但它们有不同的使用场景和效果。

防抖在您希望延迟代码执行直到用户停止执行某个动作时非常有用。例如,您可以在自动完成功能中使用防抖,等待用户停止输入后再从后端获取建议。防抖可以减少代码执行的次数,但可能会引入一些用户界面的延迟。

节流在您希望将代码执行限制在特定频率时非常有用。例如,您可以在调整页面大小时使用节流,以固定的频率更新页面布局。节流可以提高用户界面的响应性,但可能会导致一些信息或精度的丢失。

结论
防抖和节流是两种可以帮助您优化代码在短时间内重复运行性能的技术。防抖延迟代码执行直到用户停止执行某个动作一段指定的时间。节流将代码执行限制为在每个指定的时间间隔内执行一次。这两种技术有不同的使用场景和效果,您应根据具体需求选择适合的技术。

防抖 节流
防抖在再次调用函数之前等待一定时间。 节流限制在一定时间段内函数可以被调用的次数。
确保即使事件被多次触发,函数只被调用一次。 确保函数在固定的时间间隔内被调用,即使事件被多次触发。
在希望延迟调用函数直到一段静止期过去时非常有用。 在希望限制函数调用的频率时非常有用。
例如,您可以对异步API请求函数进行防抖处理,该函数在用户在输入框中输入时被调用。 例如,您可以对轮播图中用户点击按钮触发的幻灯片切换函数进行节流处理。

何时使用哪种技术

使用了一个搜索栏的示例来解释防抖和节流,通过键盘按键事件。然而,有一些特定的场景适合使用其中一种技术:

  • 防抖最适合于像输入文本或按钮点击等控制事件。
  • 节流最适合于连续的用户事件,如调整大小和滚动等。

    结论

    防抖和节流是两种可以帮助您优化代码在短时间内重复运行性能的技术。防抖延迟代码执行直到用户停止执行某个动作一段指定的时间。节流将代码执行限制为在每个指定的时间间隔内执行一次。这两种技术有不同的使用场景和效果,可以显著提升应用程序的性能,因为它们可以避免许多不必要的API调用、数据库查询等。因此,在下一个应用程序中实现事件触发时,请尝试使用它们。