调度REMOTE_DATA_STARTED操作时,我的史诗醒来,并使用action.url和action.owner获取数据.
我需要确保我不会发起对同一所有者/网址的两个并发调用.完成对所有者/网址的调用后,可以稍后为同一所有者/网址启动另一个.
取消不是我在这里寻找的,因为我不想取消现有的请求,我想阻止开始新的请求.
我觉得我需要混合使用exhaustMap和groupBy,但我不知道从哪里开始.
这是我的史诗,它拒绝所有并发呼叫,而不是所有者/网址
const myEpic = action$=>
action$.ofType("REMOTE_DATA_STARTED").exhaustMap(action =>
fakeAjaxCall().map(() => {
return { type: "COMPLETED", owner: action.owner, url: action.url };
})
);
试一试
我用一个失败的测试用例创建了这个测试项目.你能帮我做这个吗?
https://codesandbox.io/s/l71zq6x8zl
正如您将看到的,test1_exhaustMapByActionType_easy工作正常,它的test2_exhaustMapByActionTypeOwnerAndUrl失败了.
确保展开控制台以查看测试结果.
解决方法:
好的,我们走了:
GroupBy req.owner,将结果展平:
const myEpic = action$=>
action$
.ofType("REMOTE_DATA_STARTED")
.groupBy(req => req.owner)
.flatMap(ownerGroup => ownerGroup.groupBy(ownerReq => ownerReq.url))
.flatMap(urlGroup =>
urlGroup.exhaustMap(action =>
fakeAjaxCall().map(() => ({ type: "COMPLETED", owner: action.owner, url: action.url }))
)
)
不要忘记observe.complete();
const test1_exhaustMapByActionType_easy = () => {
const action$= new ActionsObservable(
Observable.create(observer => {
observer.next({ type: "REMOTE_DATA_STARTED", owner: "ownerX", url: "url1" });
observer.next({ type: "REMOTE_DATA_STARTED", owner: "ownerX", url: "url1" });
setTimeout(() => {
observer.next({ type: "REMOTE_DATA_STARTED", owner: "ownerX", url: "url1" });
observer.complete();
}, 30);
})
);
const emittedActions = [];
const epic$= myEpic(action$);
epic$.subscribe(action => emittedActions.push(action), null, () => expect("test1_exhaustMapByActionType_easy", 2, emittedActions));
};
同样在这里:
const test2_exhaustMapByActionTypeOwnerAndUrl = () => {
const action$= new ActionsObservable(
Observable.create(observer => {
// owner1 emmits 4 concurrent calls, we expect only two to COMPLETED actions; one per URL:
observer.next({ type: "REMOTE_DATA_STARTED", owner: "owner1", url: "url1" });
observer.next({ type: "REMOTE_DATA_STARTED", owner: "owner1", url: "url1" });
observer.next({ type: "REMOTE_DATA_STARTED", owner: "owner1", url: "url2" });
observer.next({ type: "REMOTE_DATA_STARTED", owner: "owner1", url: "url2" });
// owner2 emmits 2 calls at the same time as owner 1. because the two calls
// from owner2 have the same url, we expecty only one COMPLETED action
observer.next({ type: "REMOTE_DATA_STARTED", owner: "owner2", url: "url1" });
observer.next({ type: "REMOTE_DATA_STARTED", owner: "owner2", url: "url1" });
// Once all of the above calls are completed each owner makes one concurrent call
// we expect each call to go throught and generate a COMPLETED action
setTimeout(() => {
observer.next({ type: "REMOTE_DATA_STARTED", owner: "owner1", url: "url1" });
observer.next({ type: "REMOTE_DATA_STARTED", owner: "owner2", url: "url1" });
observer.complete();
}, 30);
})
);
const emittedActions = [];
const epic$= myEpic(action$);
epic$.subscribe(action => emittedActions.push(action), null, () => expect("test2_exhaustMapByActionTypeOwnerAndUrl", 5, emittedActions));
};