export
class
HttpRequestComponent
{
constructor
(
private
httpClient: HttpClient
) { }
userList
:
any
[] = [];
search
(
name
:
string
):
void
{
this
.
sendSearchRequest
(name)
.
subscribe
(
res
=>
{
this
.
userList
= res.
items
;
sendSearchRequest
(name):
Observable
<{
items
:
any
[]}> {
return
this
.
httpClient
.
get
<{
items
:
any
[]}>(
'https://api.github.com/search/users?'
, {
params
: {
q
: name
以上代码足以完成需求,但是同时有以下几种隐患。
请求效率比较低,如果我输出
netease
那么因为输入的变化,
n
,
ne
,
net
...
netease
会合计发起共7次请求。其实只要最后一次
netease
的结果。
多次请求的结果响应时间并不可控,从而渲染结果不可控。假设第一条
n
的搜索请求响应耗时10s,而其他请求包含
netease
搜索都只需要1s,那页面最终的渲染结果为n的搜索结果,显然这样是不正确的。
解决上述问题需要用到几个操作符:
export class HttpRequestComponent implements OnInit {
constructor(private httpClient: HttpClient) { }
userList: any[] = [];
private onSearch$: Subject<string> = new Subject();
search(name: string): void {
this.onSearch$.next(name);
private sendSearchRequest(name): Observable<{items: any[]}> {
return this.httpClient.get<{items: any[]}>('https://api.github.com/search/users?', {
params: {
q: name
ngOnInit(): void {
this.onSearch$.asObservable()
.pipe(
debounceTime(1000),
distinctUntilChanged(),
switchMap(name => this.sendSearchRequest(name))
.subscribe(res => {
this.userList = res.items;
Subject 有着双重特性,它同时拥有 Observer 和 Observable 的行为。(多用于组件间通信场景)
subject.next( 2 )
const subscription = subject.subscribe( (value) => console.log(value) )
debounceTime前端常见的防抖策略,在一定时间内,只保留最后一次的值。
当用户在1000ms内连续输入的时候,我们只针对最后一次输入做请求,大大提升了请求效率。
distinctUntilChanged只有值发生变化才会更新。只有内容变化才会触发请求。
部分浏览器输入中文可能会产生输入值不变,但是重复触发输入事件的问题
switchMap 有点类似于Promise。实际作用为完成前一个observable,映射成一个新的observable。
实际在angular中,当在上述的重复请求业务场景中,例如搜索,翻页等等,当前一条请求未完成,而后一条请求已经发出,那么此操作符会导致前一条请求被取消,从而保证了请求以及结果的顺序。