防抖和競態問題
防抖很重要,尤其是在前後端有網路IO的情況下,如果使用者每次操作都要往後端發一個請求,那流量費和後端伺服器壓力就會很大。標準處置方法就是加個延遲,使用者在這個時間段內的連續操作,只取最後一次(或者是最終結果)。 防抖這方面,Angular的RxJS庫裡面有搭配的方法:
// 其他引入省略
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
@Component({ ... })
export class SearchComponent {
// 1. 创建一个表单控制器,它本身就是一个 Observable 源
searchControl = new FormControl('');
// 2. 定义结果流
// 如果如果 Observable 是水管,这里的.pipe就可以理解成一个过滤器
// 进去之后进行一堆加工,最后的输出处理之后的结果
// valueChanges 负责监听值变化事件,若有则开始加工
users$ = this.searchControl.valueChanges.pipe(
// --- 管道开始 ---
// 注意下面三个是任选的,其实功能有重合,不必要全加进去
// 防抖:300ms内如果用户还在打字,就不处理
debounceTime(300),
// 去重:如果用户输入 "A" -> 删掉变成 "" -> 又输入 "A",
// 值没变,就不发请求
distinctUntilChanged(),
// SwitchMap
// 处理竞态问题,一旦有新值过来,立刻取消上一次还没完成的 HTTP 请求
// 永远只保留最后一次请求的结果
switchMap(term => {
// 如果为空,返回空数组,不发请求
if (!term) return [];
// 发起新的请求
return this.http.get<User[]>(`/api/search?q=${term}`);
})
);
constructor(private http: HttpClient) {}
}
競態問題,具體來說就是因為網路波動,導致使用者傳送的結果載入時序錯亂,導致當下請求被後返回的先前資料覆蓋的情況發生。switchMap 就是用來解決這個問題,如果數值發生變動,則上一次的請求就會直接取消,永遠只取最後一次的結果。