【问题标题】:How to correctly use Observable and Angular async pipe?如何正确使用 Observable 和 Angular 异步管道?
【发布时间】:2018-02-08 14:13:42
【问题描述】:

我尝试使用 Angular 异步管道并让它显示我使用 http get 请求从服务器获取的时间。我有以下问题:

  • 如果我想再次重新执行 http get 请求以获取更新的数据,那么在 testAsync() 中执行我正在执行的操作是否正确,或者是否有更优雅的方式来执行此操作?
  • 我还注意到在使用异步管道和重新请求数据时出现了一些闪烁。这在非异步版本(“testNormal()”)中不会发生。有什么办法可以防止这种情况发生吗?

角度组件:

    @Component({
      selector: 'app-async-test',
      templateUrl: './async-test.component.html',
      styleUrls: ['./async-test.component.scss']
    })
    export class AsyncTestComponent implements OnInit {
      private readonly baseApiUrl = environment.baseApiUrl;
      httpServerRequest$ = this.http.get<ServerTimeViewModel>(`${this.baseApiUrl}/admin/servertime`);
    
      testNormalResult: Date = null;
      testAsyncResult$: Observable<Date> = null;
      
      constructor(
        private http: HttpClient
      ) {}
    
      ngOnInit() {
          this.testAsync();
      }
    
      testNormal(): void {
        this.httpServerRequest$.subscribe(data => {
            this.testNormalResult = data.serverTime;
          });
      }
    
      testAsync(): void {   
        this.testAsyncResult$ = this.httpServerRequest$
          .map(d => d.serverTime);
      }
    }

ServerTimeViewModel 类:

    export class ServerTimeViewModel {
      serverTime: Date;
    }

模板:

    Test normal: {{ testNormalResult | date:'mediumTime'}}<br>
    Test async: {{ testAsyncResult$ | async | date:'mediumTime'}}<br>  
    <button type="button" (click)="testNormal()">test normal</button>
    <button type="button" (click)="testAsync()">test async</button>

【问题讨论】:

    标签: angular asynchronous rxjs observable


    【解决方案1】:

    https://stackoverflow.com/a/41554338/54159 这里的答案对我帮助很大。解决方案是使用 ReplaySubject。现在从 Web 服务刷新不会再导致任何闪烁。

    我已将其全部放入数据服务中。我的组件直接绑定到 dataService.person$ 并调用 dataService.fetchRandomPerson(x) 来执行一个新的 http get 请求。

    这是数据服务:

        @Injectable()
        export class DataService {
          private readonly baseApiUrl = 'https://swapi.co/api';
        
          private personSubject = new ReplaySubject<Person>(1);
          person$: Observable<Person> = this.personSubject.asObservable();
        
          constructor(
            private http: HttpClient
          ) { }
        
          fetchRandomPerson(personId: number): void {
            // re-execute http get
            // https://stackoverflow.com/a/41554338/54159
            this.http.get<Person>(`${this.baseApiUrl}/people/${personId}/`)
              .subscribe(res => this.personSubject.next(res));
            
            // note: no need to unsubscribe from http requests
            // https://stackoverflow.com/a/35043309/54159
          }
        }
    

    这是一个正在运行的版本: https://stackblitz.com/edit/angular-dpbe7t

    【讨论】:

      【解决方案2】:

      关于您的第二个问题,要消除闪烁,您应该缓存服务器响应。您可以在 angularguide 中找到更多详细信息。

      【讨论】:

        【解决方案3】:

        1。如果你想再次重新执行http get请求来获取更新的数据,我在testAsync()中做的事情是正确的,还是有更优雅的方法来做到这一点?

        考虑到这一点,你得到了一个 Observable(不是 Promise),你 不需要“重新执行http请求获取新数据”,即 数据一到达您的服务器(或其他任何 您获取数据),Observable 的目的(被观察和 观察变化)。

        2。我还注意到在使用异步管道和重新请求数据时出现了一些闪烁。这在非异步版本(“testNormal()”)中不会发生。有什么办法可以防止这种情况发生吗?

        这就是使用 Observable 的意义所在,有观察者(例如:函数)一直在​​观察数据 源数据的更改。如果你想改变这个,你可以使用 一个 Promise 代替(你仍然可以在 Angular 上使用 Promises)。此外,如果您想限制您的回复,您可以使用take operator,还有更多的请查看。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-11-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-23
          • 1970-01-01
          • 2017-11-20
          相关资源
          最近更新 更多