微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Typescript Angular,我如何调用 - 作为 Observables 链的一部分 - 对数组的每个成员进行操作并只返回成功计数?

如何解决Typescript Angular,我如何调用 - 作为 Observables 链的一部分 - 对数组的每个成员进行操作并只返回成功计数?

我需要创建一个父记录,然后创建一系列子记录(顺序不重要)。然后我需要做一个后续的日志操作。

我知道如何通过将 observable 映射在一起来在 observable 上创建一系列单个动作,因此,我可以这样做:

-- 创建一个父记录,返回其id:

createParentRecord(parentInfo: parentType): Observable<number>

-- 创建一个子记录,返回其id

createChildRecord(childInfo: childType): Observable<number>

-- 记录条目

logStuff(parentId: number,childId: number)

-- 复合函数完成所有工作,返回 parentId

doTheThing(): Observable<number> {
   /* ... */
   let parentId: number;
   let childId: number;

   return createParent(parentInfo).pipe(
     tap(id => (parentId = id)),mergeMap(id => { childInfo.parentId = parentId; return createChildRecord(childInfo);} ),mergeMap(childId => { childInfo.childId = childId; return logStuff(parentId,childId); ),map( () => parentId)
   ); 
}

问题

这很好用。

但是如果我有 childInfo[] 而不是 childInfo,我该怎么做? 如何处理要订阅并返回内部可观察结果的 childInfo[] 数组? 我只想要一个成功的数字 - 或者只是每个可观察对象返回的任何结果? 我使用 forkJoin() 吗?

我这辈子都搞不清楚。帮助?

解决方法

如果我理解正确你的问题,我会这样进行。评论是内联的

function doTheThing(): Observable<any> {
   /* ... */
   let parentId: number;
   // somehow there is an array of children info to be saved
   const childInfos = new Array(3).fill({})

   return createParent('Parent Info').pipe(
     tap(id => (parentId = id)),concatMap(id => { 
         // each childInfo is filled with the result of the createParent operation
         childInfos.forEach(c => c.parentId = parentId); 
         // an array of Observable is created - each one represents a createChildRecord operation
         const childInfosObs = childInfos.map(ci => createChildRecord(ci))
         // all child record operations are executed in parallel via forkJoin
         return forkJoin(childInfosObs);
      }),concatMap(childIds => { 
       // forkJoin returns an array of results with the same order as the array of Observables passed to forkJoin
       // therefore we can loop through the array and set each childInfo with its result
       childInfos.forEach((ci,i) => ci.childId = childIds[i])
       // last thing we do is to log and then return the results of the forkJoin
       return logStuff(parentId,childIds).pipe(
         map(() => childIds)
       );
     } )
   ); 
}

请注意,我使用 concatMap 而不是 mergeMap。除非有特定原因,否则无论何时我进行 DB 或 Rest 操作,我更喜欢 concatMap 只是为了保持操作顺序。

如果需要,您还可以使用一些错误处理逻辑来丰富 childInfosObs 中包含的每个 observable,考虑到 forkJoin 会在它尝试执行任何 Observable 时出错。

Here a stackblitz 以建议的解决方案为例。

,

块引用

您可以将 ChildInfo[] 映射到一个 observable 数组,然后像这样合并它:

return createParent(parentInfo).pipe(
  tap(newParentId => parentId = newParentId),mergeMap(newParentId => forkJoin(
   childInfos.map(childInfo => { // this is an Array map.
     childInfo.parentId = parentId;
     return createChildRecord(childInfo); // this should return childInfo,since it sounds like a CRUD operation.
   })
  )),

请注意,这仅在 createChildRecord 完成时才有效,因为 forkJoin 不会在其他情况下发出。我认为这是我的解决方案中的一个调用。 如果您让 createChildRecord 返回您的 childInfo 的更新版本,那么在以下操作中您的生活也会变得更加轻松。

createChildRecord(childInfo: ChildInfo): Observable<ChildInfo> {

  const childId = /** TBD **/
  return of({...childInfo,childId});
}

为了可读性,考虑将内部 observable 放在某种方法中。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。