给定下载管理器的示例。可以有许多主动下载。
可以派遣操作以开始,停止,标记完成并标记任何特定下载的下载进度。
const START_DOWNLOAD = "START_DOWNLOAD";
const startDownload = payload => ({ type: START_DOWNLOAD, payload });
const DOWNLOAD_PROGRESS = "DOWNLOAD_PROGRESS";
const downloadProgress = payload => ({ type: DOWNLOAD_PROGRESS, payload });
const STOP_DOWNLOAD = "STOP_DOWNLOAD";
const stopDownload = payload => ({ type: STOP_DOWNLOAD, payload });
const COMPLETE_DOWNLOAD = "COMPLETE_DOWNLOAD";
const completeDownload = payload => ({ type: COMPLETE_DOWNLOAD payload });
这些操作将包含一个ID来识别下载,并可以使用以下还原器修改REDUX状态:
const downloadReducer = (state = initialState, action) => {
switch (action.type) {
case STOP_DOWNLOAD:
return {
...state,
[action.payload.id]: {
state: "IDLE",
},
};
case START_DOWNLOAD:
return {
...state,
[action.payload.id]: {
state: "IN_PROGRESS",
progress: 0,
},
};
case DOWNLOAD_PROGRESS:
return {
...state,
[action.payload.id]: {
state: "IN_PROGRESS",
progress: action.payload.progress,
},
};
case COMPLETE_DOWNLOAD:
return {
...state,
[action.payload.id]: {
state: "DONE",
progress: 100,
},
};
default:
return state;
}
};
现在出现了有关如何使用Redux可观察到的异步调度这些动作的问题。
例如,我们可以做这样的事情:
const downloadEpic = action$ =>
action$.ofType(START_DOWNLOAD).mergeMap(action =>
downloader
.takeUntil(
action$.filter(
stop =>
stop.type === STOP_DOWNLOAD &&
stop.payload.id === action.payload.id,
),
)
.map(progress => {
if (progress === 100) {
return completeDownload({
id: action.payload.id
});
} else {
return downloadProgress({
id: action.payload.id,
progress
});
}
}),
);
这有效。但是,如果我们想限制允许的活动下载次数。我们可以用concatMap
替换mergeMap
,以一次只允许一个活动下载。或者我们可以将并发参数提供给mergeMap
,并准确指定我们要一次可观察的内下载器的执行。
但是,这带来了我们现在无法停止排队下载的问题。
我创建了一个完整的工作示例,您可以在这里尝试。
如何使用RXJS和REDUX限制和队列下载,并以最惯用的方式观察?
我已经关注了几天,但是没有时间用完整的代码给您一个可靠的答案,因为它相对涉及。因此,相反,我会给您TL; DR版本总比没有我希望的好:)
我的直觉告诉我,我将有一个UI调度一个代表尝试下载而不是真正保证的动作。例如ATTEMPT_DOWNLOAD
。史诗般的人会听取此操作,并检查当前的活动下载次数是否超过> =最大值,如果是的,则会发出一项动作以加入下载而不是启动下载。
您的还原器将存储那些活跃的人的下载ID,并下载了排队的ID。例如
{ active: ['123', '456', ...etc], queued: ['789'] }
您既要专门跟踪主动/排队,又要知道它们的计数active.length
,queued.length
当下载完成史诗般的地方时,某处会检查是否有排队的下载,如果是的,则Dequeue One。您的工作方式正是个人喜好。例如如果史诗发射DEQUEUE_DOWNLOAD
或其他。
如果派遣取消操作,您的还原器将需要查看active
和queued
,并在其中删除ID。如果实际上是活跃的,而不仅仅是排队,那么处理下载的史诗将是在聆听取消动作,它将阻止它并进行与上述相同的Dequeue检查。
这有点手动,但要点很大:
- 您的UI组件不应该在尝试之前如何或何时排队,尽管它可以通过查看Redux状态(例如显示"下载queued"或erthing)来看到事实之后
- 小心不要在多个位置重复下载的状态。例如如果它活跃,您的商店中只有一个真实的来源,说它是
- 史诗在还原器之后运行,将其用于您的优势。
- 可能会有一个史诗般的工作是唯一的工作是聆听 true 下载请求并执行该请求,而不了解排队或类似的东西。然后,该史诗将被其他多个史诗重复使用。通过将其直接称为函数,或者通过像您的真实
START_DOWNLOAD
这样的动作发出
并不总是清楚业务逻辑应该在哪里。例如还原器是否应该仅仅是Getter/Setter,还是应该具有更有意义的逻辑并做出决定?在这些情况下,没有很多规则。只是尝试保持一致。
顺便说一句,这完全来自我的肠道。我可能已经发现(或者您仍然发现)实际上这不是一个好的解决方案。只是给我最初的想法!