Javascript 两个观测值之间的差异

Javascript 两个观测值之间的差异,javascript,angular,firebase,rxjs,angular6,Javascript,Angular,Firebase,Rxjs,Angular6,假设我有两个观测值 第一个可观察到的是特定列表的数组: [ {id: 'zzz', other props here...}, {id: 'aaa', ...}, {id: '007', ...} ... and more over time ] [ {id: '007'}, // only id, no other props {id: 'zzz'} ... and more over time ] [ {id: 'aaa',

假设我有两个观测值

第一个可观察到的是特定列表的数组:

[
    {id: 'zzz', other props here...},
    {id: 'aaa', ...},
    {id: '007', ...}
    ... and more over time
]
[
    {id: '007'}, // only id, no other props
    {id: 'zzz'}
    ... and more over time
]
[
    {id: 'aaa', other props here...}
    ... and more over time
] 
第二个可观察到的是一组被忽略的列表:

[
    {id: 'zzz', other props here...},
    {id: 'aaa', ...},
    {id: '007', ...}
    ... and more over time
]
[
    {id: '007'}, // only id, no other props
    {id: 'zzz'}
    ... and more over time
]
[
    {id: 'aaa', other props here...}
    ... and more over time
] 
结果应该是一个新的可观察列表(第一个可观察列表),但不能有任何被忽略的列表:

[
    {id: 'zzz', other props here...},
    {id: 'aaa', ...},
    {id: '007', ...}
    ... and more over time
]
[
    {id: '007'}, // only id, no other props
    {id: 'zzz'}
    ... and more over time
]
[
    {id: 'aaa', other props here...}
    ... and more over time
] 
这是我现在发布之前的内容:

obs2.pipe(withLatestFrom(obs1, ? => ?, filter(?));

我没有测试,但我认为应该可以:

combineLatest(values$, excluded$).pipe(
  map(([values, excluded]) => {
    // put all the excluded IDs into a map for better perfs
    const excludedIds: Map<string, undefined> = excluded.reduce(
      (acc: Map<string, undefined>, item) => {
        acc.set(item.id, undefined)
        return acc;
      },
      new Map()
    );

    // filter the array, by looking up if the current
    // item.id is in the excluded list or not
    return values.filter(item => !excludedIds.has(item.id))
  })
)
CombineTest(值$,排除$).pipe(
映射(([值,排除])=>{
//将所有排除的ID放入映射以获得更好的性能
const excludedIds:Map=excluded.reduce(
(附件:地图,项目)=>{
附件组(项目id,未定义)
返回acc;
},
新地图()
);
//通过查找当前
//item.id是否在排除列表中
返回值.filter(item=>!excludedIds.has(item.id))
})
)
说明:

使用
combinelatetest
无论从何处获得更新,您都会收到警告。如果您在示例中使用
with latestfrom
,则仅当更新了
值$
可观察值时,才会触发更新。但是,如果
排除的$
发生更改,则不会在您的案例中触发更新

然后将所有被排除的ID放入一个映射而不是数组中,因为我们需要知道是否应该排除给定的ID。查看地图比查看数组快得多


然后只需过滤值数组。

如果我理解正确,您需要做的是

  • 随着时间的推移聚合传入的项目
  • 聚合随时间推移将被忽略的ID
  • 最后,由于上述两个流都会随着时间的推移而发出,因此会发出不包括被忽略ID的结果项列表
  • 鉴于上述情况,下面是一个粗略的例子,您可以尝试。正如在底部所指出的,根据前两个流的节奏,您将得到不同的结果,因为async就是这样。为了证明这一点,我模拟了随着时间的推移,事物发射的随机延迟

    希望这有帮助

    附言:下面是Typescript,假设是rxjs@^6

    import { BehaviorSubject, combineLatest, of, Observable } from "rxjs";
    import { delay, map, scan, concatMap } from "rxjs/operators";
    
    /**
     * Data sources
     */
    
    // Just for showcase purposes... Simulates items emitted over time
    const simulatedEmitOverTime = <T>() => (source: Observable<T>) =>
      source.pipe(
        concatMap(thing => of(thing).pipe(delay(Math.random() * 1000)))
      );
    
    interface Thing {
      id: string;
    }
    
    // Stream of things over time
    const thingsOverTime$ = of(
      { id: "zzz" },
      { id: "aaa" },
      { id: "007" }
    ).pipe(
      simulatedEmitOverTime()
    );
    
    // Stream of ignored things over time
    const ignoredThingsOverTime$ = of(
      { id: "007" },
      { id: "zzz" }
    ).pipe(
      simulatedEmitOverTime()
    );
    
    
    /**
     * Somewhere in your app
     */
    
    // Aggregate incoming things
    // `scan` takes a reducer-type function
    const aggregatedThings$ = thingsOverTime$.pipe(
      scan(
        (aggregatedThings: Thing[], incomingThing: Thing) =>
          aggregatedThings.concat(incomingThing),
        []
      )
    );
    
    // Create a Set from incoming ignored thing ids
    // A Set will allow for easy filtering over time
    const ignoredIds$ = ignoredThingsOverTime$.pipe(
      scan(
        (excludedIdSet, incomingThing: Thing) =>
          excludedIdSet.add(incomingThing.id),
        new Set<string>()
      )
    );
    
    // Combine stream and then filter out ignored ids
    const sanitizedThings$ = combineLatest(aggregatedThings$, ignoredIds$)
      .pipe(
        map(([things, ignored]) => things.filter(({ id }) => !ignored.has(id)))
      );
    
    // Subscribe where needed
    // Note: End result will vary depending on the timing of items coming in
    // over time (which is being simulated here-ish)
    sanitizedThings$.subscribe(console.log);
    
    import{BehaviorSubject,combinelateest,of,observeable}来自“rxjs”;
    从“rxjs/operators”导入{delay,map,scan,concatMap};
    /**
    *数据源
    */
    //只是为了展示的目的。。。模拟随时间发射的项目
    const simulatedEmitOverTime=()=>(来源:可观察)=>
    源管道(
    concatMap(thing=>of(thing).pipe(延迟(Math.random()*1000)))
    );
    接口事物{
    id:字符串;
    }
    //随时间推移的事物流
    const thingsOverTime$=的(
    {id:“zzz”},
    {id:“aaa”},
    {id:“007”}
    ).烟斗(
    模拟线粒体()
    );
    //随着时间的推移,被忽视的事物不断涌现
    const IgnoredThings加班$=的(
    {id:“007”},
    {id:“zzz”}
    ).烟斗(
    模拟线粒体()
    );
    /**
    *在你的应用程序中的某个地方
    */
    //聚合传入的东西
    //'scan'采用减速机类型函数
    const aggregatedThings$=thingsOverTime$.pipe(
    扫描(
    (聚合的things:Thing[],incomingThing:Thing)=>
    聚合的总含量(收入),
    []
    )
    );
    //从传入的忽略对象ID创建一个集合
    //一个集合将允许随着时间的推移轻松过滤
    const ignoredIds$=ignoredThings加班$.pipe(
    扫描(
    (不包括didset,incomingThing:Thing)=>
    excludedIdSet.add(incomingThing.id),
    新集合()
    )
    );
    //合并流,然后过滤掉被忽略的ID
    const sanitizedThings$=组合测试(聚合Things$,ignoredIds$)
    .烟斗(
    map(([things,ignored])=>things.filter({id})=>!ignored.has(id)))
    );
    //在需要的地方订阅
    //注:最终结果将根据项目进入的时间而有所不同
    //随着时间的推移(此处正在模拟)
    sanitizedThings$.subscribe(console.log);
    
    如果列表在第一个可观察对象上发出,然后在第二个可观察对象上作为忽略列表发出,该怎么办?你能保证不会发生这种情况吗?另外,由于你显然需要缓冲第二个可观察对象,你希望缓冲区永远存在(并增长)还是有条件再次删除它们(即,任何列表只能在第一个可观察对象中出现一次,基于时间的…)?