当 REMOTE_DATA_STARTED
操作被调度时,我的史诗被唤醒,它使用 action.url
和 action.owner
获取数据。
我需要确保不会对同一所有者/网址发起两个并发调用。完成对所有者/网址的调用后,稍后可以为同一所有者/网址启动另一个调用。
取消 不是我在这里寻找的,因为我不想取消现有请求,我想阻止启动新请求。
我觉得我需要 exhaustMap
和 groupBy
的混合,但我不知道从这里去哪里。
此时这是我的史诗,它拒绝所有并发调用,而不是所有者/url
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 和 exhastMap 以优雅的方式完成:
const groupedByExhaustMap = (keySelector, project) =>
source$ => source$.pipe(
groupBy(keySelector),
mergeMap(groupedCalls =>
groupedCalls.pipe(
exhaustMap(project)
)
)
);
const { delay, groupBy, mergeMap, exhaustMap } = Rx.operators;
const groupedByExhaustMap = (keySelector, project) =>
source$ => source$.pipe(
groupBy(keySelector),
mergeMap(groupedCalls =>
groupedCalls.pipe(
exhaustMap(project)
)
)
);
const calls = [ // every call takes 500ms
{startTime: 0, owner: 1, url: 'url1'},
{startTime: 200, owner: 2, url: 'url2'},
{startTime: 400, owner: 1, url: 'url1'}, // dropped
{startTime: 400, owner: 1, url: 'url2'},
{startTime: 600, owner: 1, url: 'url1'}
];
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const simulateCallsOverTime$ = Rx.Observable.from(calls)
.pipe(
mergeMap(call => Rx.Observable.of(call)
.pipe(
delay(call.startTime)
)
)
);
simulateCallsOverTime$
.pipe(
groupedByExhaustMap(
call => `${call.owner}_${call.url}`,
async call => {
await sleep(500); // http call goes here
return call;
}
)
)
.subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>
关于javascript - 如何防止从史诗开始两次相同的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49563059/