我通过以下方法获得了Angular服务:
public getItem(itemId: string): Observable<IItem> {
if (itemId== null) {
return of(null);
}
return this.store.pipe(
select(getItemFromStore(itemId)),
tap(item=> {
if (item=== undefined) {
this.store.dispath(new GetItemAction({itemId: itemId}}));
}
}),
);
}
以及捕捉动作的效果:
@Effect()
public getItem$: Observable<Action> = this.actions
.pipe(
ofType(ActionTypes.GET_ITEM),
map((action: GetItemAction) => action.payload),
exhaustMap(payload => {
return this.httpClient.get(`api/items/` + payload.itemId).pipe(
map(item => {
return new GetItemSuccessAction({ itemId: payload.itemId, item });
}),
catchError(error => {
return of(new GetItemErrorAction({ error: error }));
})
);
})
);
除了我要同时请求两个不同的项目外,这一切都很好而且很花哨,exaustMap会忽略第二个项目并且永远都不会检索它。
我该怎么写,这样对同一个项目的请求只能加载一次,但是同时对两个项目的请求都可以加载?
一个例子:
This.store.dispatch(new GetItemAction({itemId: '1'});
This.store.dispatch(new GetItemAction({itemId: '1'});
This.store.dispatch(new GetItemAction({itemId: '2'});
如果所有3个动作均已分派,则应该有2个http请求,一个针对项目1,一个针对项目2。
答案 0 :(得分:1)
您可以使用distinct
运算符。
返回一个Observable,该Observable发出源Observable发出的所有项目,这些项目与之前的项目相比是不同的。
例如:
const s = new Subject();
const source = s.pipe(
distinct(p => p.id),
concatMap(p => of(p)) // instead of `of(p)`, call the service
);
source.subscribe(x => console.log(x));
s.next({id: 1, text: 'AAA'})
s.next({id: 1, text: 'BBB'})
s.next({id: 2, text: 'CCC'})
s.next({id: 2, text: 'DDD'})
s.next({id: 1, text: 'EEE'})
s.next({id: 4, text: 'FFF'})
日志:
{id: 1, text: "AAA"}
{id: 2, text: "CCC"}
{id: 4, text: "FFF"}
这也意味着您以后将无法获取id 1
,如果您要这样做,则可以使用groupBy
:
const s = new Subject();
const source = s.pipe(
groupBy(p => p.id),
mergeMap(p => p.pipe(
exhaustMap(p => of(p).pipe(delay(1000))),
)
),
);
source.subscribe(x => console.log(x));
s.next({id: 1, text: 'AAA'})
s.next({id: 1, text: 'BBB'})
s.next({id: 2, text: 'CCC'})
s.next({id: 2, text: 'DDD'})
s.next({id: 1, text: 'EEE'})
s.next({id: 4, text: 'FFF'})
setTimeout(() => {
s.next({id: 1, text: 'AAA'})
}, 2000)
日志:
{id: 1, text: "AAA"}
{id: 2, text: "CCC"}
{id: 4, text: "FFF"}
After 2 seconds:
{id: 1, text: "AAA"}