Rxjs 防止基于先前发出的值执行

Rxjs 防止基于先前发出的值执行,rxjs,Rxjs,如果my typeahead获得的搜索结果为空,则应防止任何后续查询使用向下搜索查询。例如,如果搜索“red”返回空,则搜索“redcar”没有意义 我尝试使用pairwise()和scan()运算符。代码段: import { tap, switchMap, filter, pairwise, scan, map } from 'rxjs/operators'; this.searchForm.get('search').valueChanges .pipe( switchMap

如果my typeahead获得的搜索结果为空,则应防止任何后续查询使用向下搜索查询。例如,如果搜索“red”返回空,则搜索“redcar”没有意义

我尝试使用pairwise()和scan()运算符。代码段:

import { tap, switchMap, filter, pairwise, scan, map } from 'rxjs/operators';

this.searchForm.get('search').valueChanges
  .pipe(
    switchMap( queryString => this.backend.search(queryString))
  )
  .subscribe()
更新 给出一个简化的场景:后端只有“苹果”一词。用户正在键入搜索字符串(switchMap()不会中止请求):

  • 'a'------>后端调用返回'apple'
  • “ap”-->后端呼叫返回“apple”
  • “应用”-->后端呼叫返回“苹果”
  • “appl”-->后端调用返回“apple”
  • “apple”-->后端调用返回“apple”
  • “apple p”-->后端调用返回空
  • “apple pi”-->后端调用返回空
  • “apple pie”-->后端调用返回空
  • 后端调用7。八,。没有必要,因为6。已返回空。因此,任何后续调用都可能被忽略。在我看来,需要一些备忘录

    我想防止不必要的后端调用(http)。在rxjs中有没有实现这一点的方法?

    您可以使用操作符:

    this.searchForm.get('search').valueChanges.pipe(
    过滤器(查询=>query)
    switchMap(查询=>this.backend.search(查询字符串))
    )
    
    您可以在此处尝试此机制:

    代码共享不起作用,因此您可以在此处获取代码:

    const{of}=Rx;
    常量{filter}=RX运算符;
    of('foo1','foo2',未定义,未定义,'foo3')。管道(
    过滤器(值=>value)
    )
    
    听起来您希望保留所有失败的搜索,并检查如果调用HTTP,当前搜索是否也会失败。我想不出任何一种优雅的方式可以把它放在一条流中,但有两条流:

    _failedStreams = new Subject();
    failedStreams$ = _failedStreams.asObservable().pipe(
      scan((acc, curr) => [...acc, curr], []),
      startWith('')
    );
    
    this.searchForm.get('search').valueChanges
      .pipe(
        withLatestFrom(failedStreams$),
        switchMap([queryString, failedQueries] => {
          return iif(() => failedQueries.find(failed => failed.startsWith(queryString)) ?
            of('Not found') :
            callBackend(queryString);
          )
        }
      )
      .subscribe()
    
    callBackend(queryString) {
      this.backend.search(queryString)).pipe(
        .catchError(err => if(error.status===404) {
          this._failedStreams.next(queryString);
          // do something with error stream, for ex:
          throwError(error.status)
        }
      )
    }
    

    代码没有经过测试,但您得到了这样的想法

    这是一个有趣的用例,也是少数情况下mergeScan有用的情况之一

    基本上,您希望记住上一个搜索词和上一个远程调用结果,并根据它们的组合来决定是应该进行另一个远程调用还是只返回
    EMPTY

    import { of, EMPTY, Subject, forkJoin } from 'rxjs'; 
    import { mergeScan, tap, filter, map } from 'rxjs/operators';
    
    const source$ = new Subject();
    // Returns ['apple'] only when the entire search string is contained inside the word "apple".
    // 'apple'.indexOf('app') returns 0
    // 'apple'.indexOf('apple ap') returns -1
    const makeRemoteCall = (str: string) =>
      of('apple'.indexOf(str) === 0 ? ['apple'] : []).pipe(
        tap(results => console.log(`remote returns`, results)),
      );
    
    source$
      .pipe(
        tap(value => console.log(`searching "${value}""`)),
        mergeScan(([acc, previousValue], value: string) => {
          // console.log(acc, previousValue, value);
          return (acc === null || acc.length > 0 || previousValue.length > value.length)
            ? forkJoin([makeRemoteCall(value), of(value)]) // Make remote call and remember the previous search term
            : EMPTY;
        }, [null, '']),
        map(acc => acc[0]), // Get only the array of responses without the previous search term
        filter(results => results.length > 0), // Ignore responses that didn't find any results
      )
      .subscribe(results => console.log('results', results));
    
    source$.next('a');
    source$.next('ap');
    source$.next('app');
    source$.next('appl');
    source$.next('apple');
    source$.next('apple ');
    source$.next('apple p');
    source$.next('apple pi');
    source$.next('apple pie');
    
    setTimeout(() => source$.next('app'), 3000);
    setTimeout(() => source$.next('appl'), 4000);
    
    现场演示:


    请注意,在搜索
    “apple”
    后,将不再有远程呼叫。另外,在3秒钟后,当你尝试搜索另一个术语“app”时,它会再次进行远程调用。

    skipWhile(val=>val=='red')感谢您的更新。是否只想在返回空时阻止呼叫?因为它的措辞方式,不仅7,8是不必要的,而且2(也许3)到5也是不必要的。我就把它放在这里,虽然它并不完全符合您的要求,但这通常是人们实现类似功能的方式,可能值得一看,谢谢,但我不认为过滤器是合适的解决方案。我更新了这个问题来澄清一下。这正是我想要实现的。我尝试一下,明天提供一些反馈。嗨,朱利叶斯,虽然你的解决方案很有效,但我认为Acceped答案中的mergeScan()是以更rxjs的方式解决问题的“缺失环节”。是的,这是最好的答案+1。但我有一种不好的感觉,你的一位同事可能会开枪自杀。有些解决方案对于现实世界来说太聪明了。也许在rxjs中比在其他地方更多。我记住了这一点。