Javascript 需要为数组的每个元素执行异步函数,但只需按进度分派操作
我是RxJS的新手,仍在尝试如何使用它实现不同的功能。 我需要关于可观察的实施的帮助,尝试了很多方法,但似乎都不起作用 我有这个功能:Javascript 需要为数组的每个元素执行异步函数,但只需按进度分派操作,javascript,rxjs,observable,reactive-programming,redux-observable,Javascript,Rxjs,Observable,Reactive Programming,Redux Observable,我是RxJS的新手,仍在尝试如何使用它实现不同的功能。 我需要关于可观察的实施的帮助,尝试了很多方法,但似乎都不起作用 我有这个功能: export function automateParameterEdit(tunId) { const progress$ = new Subject(); const process$ = defer(async () => { const tun = await updateStatus(tunId, 'autoTun');
export function automateParameterEdit(tunId) {
const progress$ = new Subject();
const process$ = defer(async () => {
const tun = await updateStatus(tunId, 'autoTun');
progress$.next({ ...tun , progress: '0' });
return { rules: tun.rules, tun };
}).pipe(
flatMap(({ rules, tun }) =>
from(Object.values(rules)).pipe(
concatMap(rule => autoEditParameters(tunId, rule.ruleId, tun.rulesetId)),
scan((acc, curr) => acc + 1, 0),
map(progress => {
progress$.next({ ...tun, progress: progress / Object.values(rules).length * 100 });
}),
catchError(e => {
// whatever
}),
finalize(async () => {
// whatever
})
)
)
);
return merge(progress$, process$);
}
因此,现在,动作被调度了两次,一次是因为progress$.next({…tun,progress:progress/Object.values(rules).length*100})代码>发出新的tun进程,我认为这是因为执行了:concatMap(rule=>autoEditParameters(tunId,rule.ruleId,tun.rulesetId))
假设有4条规则(Object.values(rules.length==4
)。在控制台中,我看到4 x 2=8个已调度的操作,其中一半具有无效的负载
我想做的是执行autoEditParameters(tunId,rule.ruleId,tun.rulesetId)
哪个btw是异步的,每次执行后我想发出进度(progress$.next({…tun,progress:progress/Object.values(rules).length*100});
)
如何停止调度无效操作,并仅执行asyncautoEditParameters
和调度进度?您不需要主题
只有在需要通过流“手动”推送值时,才需要主题。但是,在您的情况下,您只需要将(map
)排放修改为不同的形状
所以,你可以摆脱这个话题。无需将进程$
与进度$
合并;您只需返回progress$
function automateParameterEdit(tunId) {
const process$ = defer(async () => {
const tun = await updateStatus(tunId, 'autoTun');
return { rules: tun.rules, tun };
}).pipe(
flatMap(({ rules, tun }) =>
from(Object.values(rules)).pipe(
concatMap(rule => autoEditParameters(tunId, rule.ruleId, tun.rulesetId)),
scan((acc, curr) => acc + 1, 0),
map(progress => {
return { ...tun, progress: progress / Object.values(rules).length * 100 };
})
)
)
);
return process$;
}
以下是几个StackBlitz示例:
每次执行后,我都要发出进度
不确定您的意思是只想发射数值百分比(不是对象),但这很容易做到。有时,将其分解为更小的函数可以使其更易于遵循:
function automateParameterEdit(tunId): Observable<number> {
return updateTun(tunId).pipe(
flatMap(processRules)
);
}
function updateTun(tunId): Observable<Tun> {
return defer(async () => updateStatus(tunId, 'autoTun'))
}
function processRules(tun: Tun): Observable<number> {
return from(tun.rules).pipe(
concatMap(rule => autoEditParameters(tun.id, rule.ruleId, tun.rulesetId)),
scan(acc => acc + 1, 0),
map(doneCount => doneCount / tun.rules.length * 100),
startWith(0),
)
}
函数automateParameterEdit(tunId):可观察{
返回updateTun(tunId).pipe(
平面图(处理规则)
);
}
函数updateTun(tunId):可观察{
返回延迟(async()=>updateStatus(tunId,'autoTun'))
}
函数processRules(tun:tun):可观察{
从(隧道规则)管道返回(
concatMap(rule=>autoEditParameters(tun.id,rule.ruleId,tun.rulesetId)),
扫描(acc=>acc+1,0),
映射(donecoount=>donecoount/tun.rules.length*100),
startWith(0),
)
}
在这里,updateTun()
只包装异步函数并返回一个可观察值,因此它将在订阅时执行
processRules()
获取一个Tun
并返回一个可观察的
,即进度百分比startWith
只发出一个初始值0
谢谢您的回答,非常有用!你能帮我再解决一个问题吗?我需要在最后调用一个函数,当所有规则都被处理后(在每个规则调用autoEditParameters之后)。我该怎么做?不客气!您可以使用finalize操作符在可观察对象完成时执行函数。所以,flatMap(processRules.pipe(finalize(yourFunction))