angular - 快速重复 HTTP 调用的 Angular/RXJS 数据问题
问题描述
我正在开发一个企业应用程序,该应用程序被另一个角度应用程序用作角度元素。
我们的应用程序从父应用程序接收一些输入,这些输入启动了一堆 api 调用,然后显示数据。我们开始遇到的一个问题是当我们从父应用程序获得快速、重复的输入时。
例如,父应用程序可能输入 {"name": "Fred", "id": "abc"},然后我们的应用程序开始使用我们在组件中订阅的 Angular 服务启动一堆 API 调用。然而,如果父组件在 {"name": "Fred", "id": "abc"} 输入,在我们的一些 API 调用完成之前。在这些情况下,我们有时会显示属于错误人员的数据。
如果有帮助或发布一些修改过的代码,我可以详细说明,不要认为我可以分享我们的实际代码。我希望得到一些关于如何处理这种情况的一般性建议或技巧。
我开始尝试做的一件事是,每次我们收到输入时检查订阅是否已经存在,重置我们所有的显示数据并取消订阅服务,然后再次开始订阅。我目前不确定这是否解决了问题。
我希望得到一些建议的另一件事是如何测试这种情况。这是可以使用 jasmine/karma 测试的东西(并且以某种方式故意操纵模拟服务中的响应时间),还是更适合 Protractor/Cypress 测试的东西?
谢谢!
编辑——这是一个不完美的 stackblitz 示例,其中 home 组件将成为焦点,它接受来自应用程序组件的输入
https://stackblitz.com/edit/angular-q4bv9y?file=src%2Fapp%2Fapp.module.ts
解决方案
这是我的方法:
export class HomeComponent {
private foodSource = new Subject<string>();
hasNoFavoriteFood = false
isLoading = false;
foodString$: Observable<string>;
@Input()
set customer(customer: Customer) {
this._customer = customer;
this.foodSource.next(
customer.hasFavoriteFood && customer.ID || null
);
}
ngOnInit () {
this.foodString$ = this.foodSource.pipe(
// You might also want to add `debounce(ms)`
// if the `setter` is called very often in a small amount of time
// debounce(300ms) // once 300ms passed without the parent sending anything, proceed to making the req
// Assumed that if `hasFavoriteFood === false`, a falsy value will be sent
tap(id => this.hasNoFavoriteFood = !id),
// Only the truthy values
filter(v => !!v)
switchMap(
id => (
this.isLoading = true,
this.customerAPI.getCustomerFoodPreferences(id).pipe(
// Adding your retry logic
retryWhen(errors$ => errors$.pipe(/* ... */)),
finalize(() => this.isLoading = false)
)
)
),
// Might want to start with a default/falsy value
startWith(null),
)
}
}
switchMap
几乎解决了你的问题。假设父级发送A
,switchMap
将创建一个内部可观察对象getCustomerFoodPreferences
。但是,当B
发送时,如果switchMap
已经有一个活动的内部 observable,它将被取消订阅并创建一个新的,基于B
.
finalize()
每当取消订阅源(在这种情况下是由 产生的可观察对象getCustomerFoodPreferences
)时都会调用。也就是说,当源发出错误/完成通知时,或者当源显式取消订阅时,这就是switchMap
新值到达时所做的事情。
你的模板会像这样使用它:
{{ foodString$ | async }}
推荐阅读
- python - 按值和大小的递增顺序对嵌套的数字列表进行排序
- javascript - 每当在 d3 v6.3.1 中更新数组时,如何更新条形图数据?
- python - 根据 Python 中另一个数据框的列表更新较早日期的值
- asp.net-core-mvc - 如何获取 asp.net 身份以从数据库中获取对声明的更改?
- javascript - NuxtJS 在特定滚动位置显示替代导航栏不起作用
- python - 避免`can't open camera by index`,用cv2测试时,所有cam都连接
- asp.net - ConfigureAwait(false) 如何防止 UI 死锁
- javascript - 如何在jquery中动态添加表单元素?
- reactjs - TypeScript:对象的类型为“未知”.ts(2571)
- azure-blob-storage - 当文件在 Blob 存储中被修改时自动触发快照