RxJS 中的 Debounce
在 Web 开发中,我们经常需要处理一些用户输入或者事件触发的情况,例如搜索框的联想、下拉框的展示、滚动加载等等。这些场景下,我们往往需要防止用户短时间多次触发事件,导致不必要的请求或者响应过快。这时候,RxJS 中的 Debounce 操作符就能够起到很好的作用。
Debounce 操作符是什么?
Debounce 操作符是 RxJS 中的一种操作符,它能够让 observable 序列中的事件延迟一段时间后才被触发,如果在这段时间内又有新的事件发生,它会丢弃掉上一个事件,只触发最近的一个事件。这个“阈值”时间就是 debounce 的参数,通常可以设置为几百毫秒或者几秒。
Debounce 的应用场景
Debounce 常常用于处理输入框搜索联想、滚动加载、鼠标点击等场景。
输入框搜索联想
在搜索框中,我们往往需要在用户输入完成后触发搜索联想,如果用户输入太快,可能会导致多次请求以及 UI 卡顿等问题。这时候就可以使用 debounce 操作符,通过设置一定的时间阈值,使得用户在输入时不会频繁触发请求。
// javascriptcn.com 代码示例 import { fromEvent } from 'rxjs'; import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators'; const searchBox = document.getElementById('search-box'); const searchResult = document.getElementById('search-result'); const search$ = fromEvent(searchBox, 'input').pipe( debounceTime(500), // 防抖 distinctUntilChanged(), // 过滤重复请求 switchMap((event) => fetch(`/search?wd=${(event.target as HTMLInputElement).value}`)) ); search$.subscribe((response) => { searchResult.innerHTML = response; });
在这个例子中,我们通过 fromEvent 创建输入框的 observable 序列,然后调用 debounceTime(500) 使用户输入停止 500ms 后再发出事件,再使用 distinctUntilChanged 过滤掉相同的搜索关键字,最后使用 switchMap 发起网络请求,并将结果赋值给搜索结果容器。
滚动加载
在滚动加载的场景中,我们往往需要在滚动到页面底部时触发新的加载,如果使用普通的事件监听,可能会出现过于频繁和卡顿的情况。Debounce 可以帮助我们优化这一过程,通过设置一定的时间阈值进行事件的延迟触发。
// javascriptcn.com 代码示例 import { fromEvent, merge } from 'rxjs'; import { mapTo, throttleTime } from 'rxjs/operators'; const scroll$ = fromEvent(document, 'scroll').pipe( throttleTime(100), // 节流 mapTo(1) ); const resize$ = fromEvent(window, 'resize').pipe( throttleTime(100), // 节流 mapTo(1) ); const window$ = merge(scroll$, resize$).pipe( debounceTime(500) // 防抖 ); window$.subscribe(() => { console.log('Load more!'); });
在这个例子中,我们使用 fromEvent 创建 document 和 window 的 observable 序列,然后使用 throttleTime 响应滚动和 resize 事件,避免频繁触发事件,最后使用 merge 合并两个 observable 序列,再调用 debounceTime(500) 进行 debounce,避免短时间内频繁触发事件并执行加载操作。
总结
Debounce 操作符能够在一些需要避免用户频繁触发事件的场景中发挥很好的作用,避免出现过多请求、卡顿等不必要的问题。同时,我们也需要注意 debounceTime 的阈值设置,避免延迟时间过长或过短导致用户体验下降。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653ecb977d4982a6eb82f18a