Javascript 需要为数组的每个元素执行异步函数,但只需按进度分派操作

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');

我是RxJS的新手,仍在尝试如何使用它实现不同的功能。 我需要关于可观察的实施的帮助,尝试了很多方法,但似乎都不起作用

我有这个功能:

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});


如何停止调度无效操作,并仅执行async
autoEditParameters
和调度进度?

您不需要
主题

只有在需要通过流“手动”推送值时,才需要主题。但是,在您的情况下,您只需要将(
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))