【问题标题】:Waiting subscribe inside a foreach to end在 foreach 中等待订阅结束
【发布时间】:2020-12-04 21:43:04
【问题描述】:

所以我在 rxjs 方面是新的,我知道我的问题的答案可能涉及到管道。但是,我已经这样做了,但从来没有工作过。我的方法是在地图中绘制路径like this

为此,我需要从我的数据库中获取所有行并获取linePaths like this 的数组。之后我在该数组中获取 pathKey,然后我 findByKey 路径并获取 pathObjects 列表。每个 pathObject 都包含一个数组 pathNodes like this.. 所以我要做的是进入每个 pathNode 并通过 pathNode 包含的键获取 NodeObject。我这样做是因为每个节点都包含要在地图上标记的纬度和经度。例如,在最后一张图片中,我发送 Node1 连接到 Node:15 连接到 Node:13 等等。问题是我试图在 forEach 中进行订阅,因此我的程序有点爆炸。当我 F5 时显示了许多解决方案,当我尝试通过 pathNodes 中的最后一个节点结束路径时,它让我将该列表的 lastNode 连接到另一个 PathNodeArray 的开始节点。

我要展示我的代码示例

this.lineService.getAll()
  .subscribe(
    data => {
      this.lines = data;
      //console.log(this.lines);
      this.lines.forEach((element: any) => element.linePaths[0].linePath.forEach((element: any) => {
        //console.log(element);
        this.pathService.findByKey(element.path)
          .subscribe(
            data => {
              this.paths = data;
              //console.log(this.paths);
              let observables: Observable < any > [] = [];
              this.paths.pathNodes[0].pathNode.forEach((element: any) => {
                //console.log(element);
                observables.push(element.node);
              })
              const arrayToStore: any = [];
              observables.forEach((element: any) => {
                this.nodeService.findByKey(element)
                  .subscribe(
                    (data: any) => {
                      this.nodeToSearch = data;
                      arrayToStore.push(data);
                      for (let i = 0; i < arrayToStore.length - 1; i++) {
                        L.polyline([
                          [arrayToStore[i].latitude, arrayToStore[i].longitude],
                          [arrayToStore[i + 1].latitude, arrayToStore[i + 1].longitude]
                        ]).addTo(this.map);
                      }
                    });
              })
            }
          )
      }));
    });

我的问题显示的示例是这个:

observables.forEach((element: any) => {
  this.nodeService.findByKey(element)
    .subscribe(
      (data: any) => {
        this.nodeToSearch = data;
        arrayToStore.push(data);
        for (let i = 0; i < arrayToStore.length - 1; i++) {

          L.polyline([
            [arrayToStore[i].latitude, arrayToStore[i].longitude],
            [arrayToStore[i + 1].latitude, arrayToStore[i + 1].longitude]
          ]).addTo(this.map);
        }
      }
    );
})

【问题讨论】:

    标签: javascript angular rxjs


    【解决方案1】:

    您有一个复杂的对象,所以我不知道代码是否可以帮助您。了解“thecnica”很重要,因为数据库中的更改会使代码无法正常工作。

    为了简化,你可以在你的 dbs 中声明三个 observables

    const getAll=()=>this.lineService.getAll().pipe(map(x=>(
    {
      name:x.name
      linePath:x.linePaths[0].linePath
    })))
    const getPath=(key)=>this.pathService.findByKey(key).pipe(map(x=>(
    {
      key:x.key
      nodes:x.pathNodes[0].pathNode
    })))
    const getNode=(key)=>this.nodeService.findByKey(key).pipe(map(x=>(
    {
      key:x.key
      lat:....  //I dont know how is the data from nodeService
      long:...
    })))
    

    所以这个函数返回更简单的对象

    getAll() give object like
       [{name: "lordedo",linePath: [{ key: "path1" }, { key: "path2" }, { key: "path3" }]}..]
    getPath(key) give object like
       {key:"path1",nodes:[{key:"node1"},{key:"node2",duration:10},{key:"node3",duration:20}]
    and getNode(key) give object like
       {key:"node1",lat:10,long:20}
    

    我会尝试将 cmets 放到代码中以帮助理解,但想法是:当我们得到 obs 时,

    1. 使用 switchMap
    2. 创建一个“键”数组
    3. 创建数组的 forkJon
    4. 使用从 forkJoin 接收到的数据转换键数组
    5. 返回数组

    代码是

    this.paths=getAll().pipe(switchMap(lines=>{
      const pathsKeys=lines.map(x=>x.linePath.map(x=>x.key))
        .reduce((a,b)=>[...a,...b])
        //in pathsKeys we has ["path1","path2","path3"...]
        return forkJoin(pathsKeys.map(path=>getPath(path))).pipe(
          switchMap(pathsData=>{
            //pathsData is an array [{key:..,nodes:{key:..},{key:..,nodes:{key:..}...]
            const nodesKeys=pathsData.map(x=>x.nodes).reduce((a,b)=>[...a,...b])
               .map(x=>x.key)
            //nodesKey is an array with values repeats ["node1","node2","node1","node3"..]
            const nodesUniq=nodesKeys
               .filter((n,index)=>nodesKeys.indexOf(n)==index)
            //nodes uniq are an array with uniq values ["node1","node2",...]
            return forkJoin(nodesUniq.map(x=>getNode(x))).pipe(map((nodesData:any)=>{
              //nodesData is an array with the data of the nodes
              //[{key:..,lat:..,long:..},{key:..,lat:..,long:..}...]
    
              //we are going to transform "lines"
              //remember: in pathsData we have an array with the data of the paths
              //          in nodesData we has an array with the data of the nodes
              lines.forEach(line=>{
                line.linePath.forEach(p=>{
                  //for each line we add the property "nodes" and "duration"
                  const path=pathsData.find(x=>x.key==p.key)
                  p["nodes"]=[...path.nodes]
                  p["duration"]=0
                  p["nodes"].forEach(n=>{
                    p["duration"]=p["duration"]+(n.duration?n.duration:0)
                    delete n.duration
                    const node=nodesData.find(y=>y.key==n.key)
                    //for each node we add the properties "lat" and "long"
                    n["lat"]=node["lat"]
                    n["long"]=node["long"]
                  })
                })
              })
              return lines
            }))
          })
        )
    }))
    

    如果我们订阅 this.paths 我们会得到我们需要的数据

    你可以在this stackblitz看到

    【讨论】:

      猜你喜欢
      • 2018-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-22
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 1970-01-01
      相关资源
      最近更新 更多