【问题标题】:How to preload a portion of data in Angular while loading the rest?如何在加载其余数据时在 Angular 中预加载一部分数据?
【发布时间】:2020-02-07 21:24:06
【问题描述】:

当我尝试加载第一页数据并在后台加载整个数据集时显示它时,我认为我很聪明。我使用了以下代码。

ngOnInit() {
  this.service.getStuff(0, 10)
    .subscribe(suc => this.subset = suc);

  this.service.getStuff()
    .subscribe(suc => this.data = suc);
}

然后,我在我的 API 中设置断点,获取并释放第一个调用并保持未释放的第二个调用。但是,根据我浏览器中的网络选项卡,两个调用都待处理,直到两个调用都完成。

我离预载工作很近还是很远?

实际调用是通过通常的 HttpClient 和 GET 执行的,返回一个 observable。

【问题讨论】:

  • 您所描述的不是预期的行为。其他事情正在发生。
  • @bryan60 我根据答案和评论收集到这一点。我注意到由于 timer(1000).subscribe(...) 而调用第二个调用产生了预期的行为,因此不知何故,计算机将这两个调用阻塞在一起。您正在确认我最初的期望(我放弃了,因为我最终变得不确定并对自己的技能失去信心)。我很想建立一个可重现的例子,但我不知道怎么做,因为这是一个结合 .NET 和 Angular 的问题......
  • 多年来我一直在使用 .NET 后端处理 Angular,但从未遇到过这样的问题。这可能与您在 API 中设置喙点的方式有关,或者您是否有某种不守规矩的拦截器,或者您的服务中发生的某些事情阻碍了 http 客户端。

标签: angular httpclient


【解决方案1】:

你最好使用一些 RxJS 操作符。

这将触发两个 GET。先到先得。

merge(this.service.getStuff(0, 10), this.service.getStuff()).subscribe(data => {
  // do stuff with data
});

下面,switchMap 将使 allStuff$ 仅在 initialStuff$ 发出后触发。 这将仅在第一个 GET 发出后触发第二个 GET。

const intialStuff$ = this.service.getStuff(0, 10).pipe(
  share()
);

const allStuff$ = intialStuff$.pipe(
  switchMap(() => this.service.getStuff())
);

intialStuff$.subscribe(...);
allStuff$.subscribe(...)

请注意,由于没有任何请求会阻塞渲染,因此您绝对应该使用第一种方法。它将更快地获取所有数据。

【讨论】:

  • 我会再试一次。据我所见,第二个更大的调用(我通过简单地在后端放置一个断点并让它挂起来停止)在网络选项卡中列为待处理(应该如此)。出乎意料的是,从断点释放并应该返回的第一个调用也被列为待处理。
  • 这太奇怪了。我仍然会得到相同的意外行为但是如果我在 timer(4000).subscribe(_ => this.service.getStuff()...) 之后执行第二次调用然后我得到了预期的结果。就像 Angular 将这两个调用捆绑在一起,除非其中一个调用设置在计时器上......老实说,我不太理解。
  • RxJS 将捆绑它们,除非您使用诸如 switchMap/concatMap/mergeMap 之类的扁平化操作符。那些运营商说,在一个源 observable 发出之后,然后订阅另一个。实际触发 HTTP 请求的是订阅行为。这种可观察的质量(订阅创建新的数据生产者)被称为“热可观察”,适用于所有 HTTP 请求。
  • 关于您的陈述“实际上触发 HTTP 请求的是订阅行为。”,我完全同意。然而,令我惊讶的是,基于此,我的问题样本应该彼此独立地触发两次。然而,事实并非如此。或者,更确切地说,调用的状态被标记为pending,并且不会为第一次调用呈现信息,直到第二次调用完成。我怀疑这与我以某种方式在开发模式下在本地主机上运行所有内容有关。将它设置为一个单独的项目会很好,但我不知道如何(.NET back/Angular front)。
  • 为了这个特定的目的,我使用了第一个基于 merge 的示例。按预期工作。但是,我尝试在不同的情况下应用基于 switchMapshare 的第二个示例(从路由中获取 ID,然后将其作为参数加载数据) .遗憾的是,它没有按我希望的方式工作,所以我想知道你是否有时间take a peek at it 看看我是如何错过你的观点的。
【解决方案2】:

Angular HttpClients get() 每次都应该返回一个新的 Observable,并且不会表现出您描述的行为。

这完全取决于this.service.getStuff() 的实现。如果实现如下所示,它应该在每次调用时返回一个新的Observable,并使其独立于任何其他调用/订阅。

doStuff() {
    return this.http.get('someUrl');
}

Here's an example of the two observable calls working independent of each other - 我延迟了帮助演示。当您运行它时,第一次调用将完成并在第二次调用之前呈现。

具有初始化逻辑的组件:

ngOnInit(){
this.myService.doSomething('todos/1', 100)
  .subscribe(resp => {
    this.first = resp;
  });

this.myService.doSomething('comments', 1500)
  .subscribe(resp => {
    this.second = resp;
  })
}

示例服务:

@Injectable()
export class MyService {
  constructor(private http: HttpClient){}

  doSomething(route: string, withDelay?: number) {
    return this.http.get('https://jsonplaceholder.typicode.com/' + route)
      .pipe(delay(withDelay));
 }
}

【讨论】:

  • 是的,这就是我所期望的。我没有用服务方法的延迟来测试它,只是在我正在调用的控制器中设置了一个断点。但这不应该有任何区别 - 一旦从 WebAPI 调度第一次调用,它应该呈现在客户端的屏幕上。不知道如何为此设置 StackBlitz(包括要调用的实际后端)...
  • 我发现我并不清楚。当我运行您的 Blitzy 时,我可以在网络选项卡中看到两个响应同时到达(至少看起来如此)。然后,在屏幕上呈现第二个之前需要一定的延迟。但是,我的目标并没有延迟演绎。它正在为第一个调用调用演绎,而第二个调用正在进行中。您是否知道一种方法可以使您在示例中调用的后端对于某些调用变得超级慢?
猜你喜欢
  • 2015-11-02
  • 1970-01-01
  • 2023-02-10
  • 1970-01-01
  • 1970-01-01
  • 2022-08-17
  • 1970-01-01
  • 1970-01-01
  • 2017-12-03
相关资源
最近更新 更多