如何正确使用Observable和Angular异步管道?

时间:2018-02-08 14:13:43

标签: angular asynchronous rxjs observable

我尝试使用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>

3 个答案:

答案 0 :(得分:2)

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

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

这是DataService:

@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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

  

考虑到这一点,你得到了一个Observable(而不是Promise),你   不需要&#34;重新执行http请求以获取新数据&#34;,即   数据即将到达您的服务器(或其他任何东西)   你来源数据),一个Observable的目的(被观察和   看着变化)。

<强> 2 即可。此外,我注意到在使用异步管道并重新请求数据时会发生一些闪烁。这种情况不会发生在非异步版本中(&#34; testNormal()&#34;)。有什么办法可以防止这种情况发生吗?

  

这是使用Observable的观点,有观察者(Ex:函数)总是在观察数据   您的源数据更改。如果你想改变它,你可以使用   改为承诺(你仍然可以在Angular上使用Promises)。另外,如果你想限制你的回复,你可以使用take operator,还有更多只是检查它们。