代码之家  ›  专栏  ›  技术社区  ›  Jscti

RXJS 6:数组的递归筛选。。使用异步筛选器

  •  0
  • Jscti  · 技术社区  · 6 年前

    我需要过滤对象的递归数组。

    复杂的部分是过滤需要一个异步函数调用(我在我的项目中有这个特定的需求)。 这就是为什么我试着用RXJS实现它,但我可以用标准数组函数+async/await实现它。。。

    我还借此机会学习了更多的rxjs,这就是为什么我想要一个面向rxjs的答案(这是一个处理异步的好方法?)。谢谢

    具有此阵列:

    [
          {
            id: 'level 1.1',
            permission: true,
            children: [
              {
                id: 'level 2.1',
                permission: false,
                children: [
                  {id: 'level 3.1'}
                ]
              },
              {
                id: 'level 2.2',
                permission: true,
                children: [
                  {id: 'level 3.2'}
                ]
              }
            ]
          },
          {
            id: 'level 1.2'
          },
          {
            id: 'level 1.3',
            permission: false
          }
        ]
    

    [
          {
            id: 'level 1.1',
            permission: true,
            children: [
              {
                id: 'level 2.2',
                permission: true,
                children: [
                  {id: 'level 3.2'}
                ]
              }
            ]
          },
          {
            id: 'level 1.2'
          }
        ]
    

    我尝试的方法在没有递归(注释代码)的情况下工作,因此成功过滤了第一级,但我不知道如何添加递归:

    // simplified ASYNC filter function
    promiseMe(x) {
        return Promise.resolve().then(() => {
          return x.permission === undefined || x.permission === true
        });
    }
    
    // recursive function
    const recursive = arr => {
        return from(arr).pipe(
            mergeMap(entry => from(this.promiseMe(entry)).pipe(
                tap(y => console.log(y)),
                filter(Boolean),
                mapTo(entry),
                tap(console.log),
                mergeMap(item => {
                    // here I'm lost
                    // I need to affect the result of my async recursive function to item.children : 
                  /*return recursive(item.children).pipe(
                      tap(res => {
                        console.log('RES', item, res)
                        item.children = res;
                      })
                    );*/
    
                    return of(item);
                })
            )),
            toArray()
        )
    };
    
    // main call
    recursive(arr).subscribe(x => console.log('finally', x, JSON.stringify(x)))
    

    在这里拉小提琴: https://stackblitz.com/edit/angular6-rxjs6-playground-idysbh?file=app/hello.component.ts

    1 回复  |  直到 6 年前
        1
  •  3
  •   Yanis-git    6 年前

    我不明白为什么你需要RxJS来处理你的列表。

    我建议这项实施:

    const source = [
        {
          id: 'level 1.1',
          permission: true,
          children: [
            {
              id: 'level 2.1',
              permission: false,
              children: [
                {id: 'level 3.1'}
              ]
            },
            {
              id: 'level 2.2',
              permission: true,
              children: [
                {id: 'level 3.2'}
              ]
            }
          ]
        },
        {
          id: 'level 1.2'
        },
        {
          id: 'level 1.3',
          permission: false
        }
    ];
    
    const isAllow = item => {
      return item.permission === undefined || item.permission;
    };
    
    const filtering = (list) => {
      const listing = [];
      list.forEach(item => {
        // If current one have permission.
        if(isAllow(item)) {
          // If he have child, let process it recursively.
          if(item.children && item.children.length > 0) {
            item.children = filtering(item.children);
          }
          // Add current on to whitelisted.
          listing.push(item);
        }
      });
      return listing;
    };
    
    console.log(filtering(source));
    

    如果您想在rxjs流上打开此列表,只需使用 map :

    of(source).pipe(map(source => filtering(source))).subscribe(console.log)
    

    编辑一个:

    基于澄清,我已经以可观察的方式完成了上述代码。

    allowOnly$ )其中:

    • concatMap
    • filter 不允许的项目。
    • 海图 又是新的 combineLatest 它们是当前项和的递归调用的组合 随意地$ 以所有子对象作为参数。
    • toArray

    const dummyAjaxRequest = (item) => {
      return of({
          ...item,
          permission: (item.permission === undefined || item.permission)?true:false
          });
    }
    
    const allowOnly$ = items => {
      return from(items).pipe(concatMap(item => {
        return from(
          /**
           * Perform your ajax request here to find what's is allow or not.
           */
          dummyAjaxRequest(item)
        ).pipe(
          /**
           * Exclude what is not allowed;
           */
          filter(item => item.permission),
          concatMap(item => {
            /**
             * If we have child, perform recursive.
             */
            if (item.children) {
              /**
               * combine child and parent.
               */
              return combineLatest(
                allowOnly$(item.children), // Recursive call.
                of(item)
              ).pipe(map(i => {
                return {
                  ...i[1], // all property of current,
                  children : [...i[0]] // Create new array base on allowed childrens.
                };
              }))
            }
            else {
              /**
               * No child, return simple observable of current item.
               */
              return of(item);
            }
          })
        );
      }), toArray()); // transform stream like --|-|-|-> to --[|,|,|]->
    };
    
    of(source).pipe(concatMap(items => {
      return allowOnly$(items);
    })).subscribe(console.log);
    

    重要提示所有 mergeMap 你要换成什么 海图