如何在等待响应时取消http.post()?

时间:2018-10-30 02:16:51

标签: angular rxjs angular6 rxjs5

这是来自角度组件的一些代码。它是一个搜索组件,其中characterIndexes是搜索结果的数组。

通过在搜索框中键入搜索内容来检索搜索结果,该搜索框根据内容触发searchtriggersearchEmptyTrigger。得到第一个结果后,我必须执行另一个http.post()来获取属于索引的名称,以便对它们进行排序(我从代码中省略了该部分)。然后将结果插入characterIndex数组中。

触发searchEmptyTrigger时也会发生类似的情况。 characterIndex数组只是设置为空,不需要http请求。

我遇到的问题是,在某些情况下,当触发searchEmptyTrigger时,searchtrigger中的代码仍在运行(由于http请求导致的延迟)。

结果是characterIndexes首先为空。然后在收到searchtrigger中来自http请求的结果后,它将再次填充。

因此,最大的问题是:'如何在正在等待响应的情况下取消正在运行的http.post()?'

  public characters: any[];
  public characterIndexes: number[];

  let searchBox = document.getElementById('search-box');
  let searchTrigger = fromEvent(searchBox, 'input')
  .pipe(
    map((event: any) => event.target.value ),
    filter( text => text.length > 2 ),
    debounceTime( 500 ),
    distinctUntilChanged(),
    switchMap( text =>  ajax(`https://esi.evetech.net/v2/search/?categories=character&datasource=tranquility&language=en-us&search=^${text}&strict=false`)
    )
  );

  let searchEmptyTrigger = fromEvent(searchBox, 'input')
  .pipe(
    map((event: any) => event.target.value ),
    filter( text => text.length <= 2 )
  );

  searchTrigger.subscribe( response => {
    if( response.response.character ){
      let characterIndexes = response.response.character;
        this.http.post('https://esi.evetech.net/latest/universe/names/?datasource=tranquility', characterIndexes)
        .subscribe( (charactersInfo: any[]) => {
           // do some stuff with this.characterIndexes and this.characters = [];
        });
      } else {
        this.characterIndexes = [];
        this.characters = [];
      }
    });

    searchEmptyTrigger.subscribe( () => {
      // reset values 
      this.characterIndexes = [];
      this.characters = [];
    });

PS:我也愿意接受一种替代方法,该方法执行与上面的代码相同的操作,在此我可以取消http请求。

3 个答案:

答案 0 :(得分:1)

我认为您应该使用/* Container */ .links { display: flex; flex-direction: column; flex-wrap: wrap; width: 100vw !important; height: 90vh; } /* Links in Container */ .links a { white-space: nowrap; flex: 1; margin: 5px 5px 0 20px; }

takeUntil(searchEmptyTrigger)

PS,您可以将整个代码完全简化为更少的代码。

不要将this.http.post('https://esi.evetech.net/latest/universe/names/?datasource=tranquility', characterIndexes) .pipe(takeUntil(searchEmptyTrigger)) // make sure to cancel the post if `searchEmptyTrigger` emits .subscribe( (charactersInfo: any[]) => { // do some stuff with this.characterIndexes and this.characters = []; }); 放在另一个subscription中,就像您的subscription请求一样。

您可以使用运算符将​​它们合并。 我很懒惰,:d

答案 1 :(得分:0)

尝试这种方式...

示例::概念是unsubscribe观察对象...

const request = this.searchService.search(this.searchField.value)
  .subscribe(
    result => { this.result = result.artists.items; },
    err => { this.errorMessage = err.message; },
    () => { console.log('Completed'); }
  );

  request.unsubscribe();  // <-- Hear you can cancel the API request.. 
  //Just set in when you need to cancel. It will works fine. 
  // E.x use with timeout or delay option of observable. 
}

答案 2 :(得分:0)

我想我明白了。首先,我将尝试解释发生了什么问题,然后再解决问题。

问题

在问题的代码中有问题。在发出新值之前,我应该已经在searchTrigger中执行了http请求,但是没有在searchTriggerEmpty中执行了。因此,searchTrigger可能会在searchTriggerEmpty甚至是最先启动searchTrigger的情况下发出。

解决方案

解决方案是确定发射顺序。为此,必须在发出任何请求之前发出事件。并且当触发新事件时,应取消上一个事件(switchMap-behavior)。

代码说明

  • 当有人输入searchTrigger时会发出事件 searchBox
  • 添加了一些管道。 debounceTime( 500 )distinctUntilChanged()防止事件触发过多。
  • map管道返回searchBox中的值类型。
  • switchMap内有一个条件语句。这是选择最佳进行方式的地方。
  • 如果字符串长于2个字符,它将返回一个可观察到的characterIndexes数组(它通过执行一些http请求并对其进行处理来获取它们)。
  • 如果字符串少于2个字符,它将直接返回一个空数组。
  • 此处使用switchMap的原因是,当发出新值时,当前挂起的进程将被取消。
  • 通过订阅searchTrigger,我们现在可以处理最新的搜索结果。
  • 我还提供了用于process_searchString()的功能,因此您可以更好地了解它的作用/返回什么。

代码

let searchBox = document.getElementById('search-box');
let searchTrigger = fromEvent(searchBox, 'input')
.pipe(
  debounceTime( 500 ),
  distinctUntilChanged(),
  map((event: any) => event.target.value ),
  switchMap( searchString => {
    if( searchString.length > 2 ){
      return this.process_searchString( searchString );
    } else if ( searchString.length <= 2 ) {
      return of( [] );
    }
  }),
);

searchTrigger.subscribe( ( characterIndexes: number[] ) => {
  this.characterIndexes = characterIndexes;
  this.characters = [];
  if( characterIndexes.length > 0 ){
    this.load_10characters();
  }
});

免责声明:在撰写本文时,我刚刚学会了使用rxjs。因此,如果您看到任何需要改进的地方,请在评论中添加。

PS:对于那些感兴趣的人来说,此视频比我能更好地解释switchMap(并且也很有趣):https://www.youtube.com/watch?v=rUZ9CjcaCEw

额外的process_searchString()

  private process_searchString( searchString: string ): Observable<number[]>{
    return new BehaviorSubject( searchString )
    .pipe(
      concatMap( ( text: string ) => this.request_characterSearch( text ) ),
      concatMap( ( response: any ) => {
        if( response.character ){
          return this.request_characterNames( response.character )
        } else {
          return of([]);
        }
      }),
      map( (charactersInfo: any[]) => this.sort_alphabetically( charactersInfo ) ),
      map( (charactersInfo: any[]) => charactersInfo.map( characterinfo => characterinfo.id ) ),
    );
  }