递归等待订阅集完成

Wait for Subscription set Recursively to Complete

我有一个包含子对象的对象数组,需要递归地在每个对象中设置一个字段(隐藏)。每个值都在订阅中设置。我想等到数组中的每一项都被递归更新后,订阅才完成。

隐藏字段将根据从另一个可观察对象派生的角色和权限进行设置。在示例中,我添加了一个延迟来模拟它。

这是我的第一遍。我确信有一种更简洁的方法来解决这个问题。

https://codesandbox.io/s/rxjs-playground-hp3wr

// Array structure. Note children.
const navigation = [
  {
    id: "applications",
    title: "Applications",
    children: [
      {
        id: "dashboard",
        title: "Dashboard"
      },
      {
        id: "clients",
        title: "Clients"
      },
      {
        id: "documents",
        title: "Documents",
        children: [
          {
            id: "dashboard",
            title: "Dashboard"
          },...
        ]
      },
      {
        id: "reports",
        title: "Reports"
      },
      {
        id: "resources",
        title: "Resources"
      }
    ]
  }
];

在代码沙箱示例中,查看控制台消息,我得到了正确的结果。但是,我想避免必须订阅 setHidden 和 recursivelySetHidden。我也想尽可能避免使用 Subject。

这是我的方法:

const roleObservable = timer(1000).pipe(mapTo("**************"));

function populateWithField(o, field, fieldValue) {
  if (Array.isArray(o)) {
    return from(o).pipe(
      concatMap(c => populateWithField(c, field, fieldValue)),
      toArray()
    );
  }

  if (o.children) {
    return roleObservable.pipe(
      tap(role => (fieldValue = role)),
      concatMap(role => populateWithField(o.children, field, role)),
      map(children => ({
        ...o,
        [field]: fieldValue,
        children
      }))
    );
  }

  return roleObservable.pipe(
    map(role => ({
      [field]: role,
      ...o
    }))
  );
}

of(navigation)
  .pipe(concatMap(o => populateWithField(o, "hidden")))
  .subscribe(console.log, e => console.error(e.message));

要注意的主要事情是 concatMap. It it a higher-order mapping operator 的频繁使用,这意味着,除其他事项外,它将自动从其内部可观察对象订阅 to/unsubscribe。

concatMap 与其他运算符的不同之处在于,它 保留发出值的缓冲区 ,这意味着它将 等待 用于 当前内部可观察对象 在订阅下一个之前完成。

在这种情况下,您将不得不处理很多 Observables-of-Observables(higher-order observables),这就是 为什么 您必须使用 concatMap每次遇到一个children属性。 属性 中的任何 child 都可以有自己的 children 属性,因此您必须确保 Observable 仅包含 first-order 可观测值。

您可以阅读更多关于 higher-order 和 first-order observables here

Here is a CodeSandbox example