在RxJS中,如何防止操作员在源可观测数据没有';你没有吗?

在RxJS中,如何防止操作员在源可观测数据没有';你没有吗?,rxjs,rxjs6,Rxjs,Rxjs6,我有三个可观察对象,foo$、bar$和baz$,我将它们合并在一起形成另一个可观察对象。这是预期的工作: 流以>> 每个值一个接一个地发出 流以{ console.log(str); }); const{merge,of}=rxjs;const{startWith,endWith}=rxjs.operators来自startWith的文档: 返回一个Observable,该Observable在开始发出源Observable发出的项之前发出您指定为参数的项 因此,startWith和end

我有三个可观察对象,
foo$
bar$
baz$
,我将它们合并在一起形成另一个可观察对象。这是预期的工作:

  • 流以
    >>
  • 每个值一个接一个地发出
  • 流以
    {
    console.log(str);
    });
    
    
    
    const{merge,of}=rxjs;const{startWith,endWith}=rxjs.operators来自
    startWith
    的文档:

    返回一个Observable,该Observable在开始发出源Observable发出的项之前发出您指定为参数的项

    因此,
    startWith
    endWith
    将始终运行

    我不知道您期望的结果应该是什么,但是如果您只想为每个发出的值连接字符串,您可以使用
    map
    switchMap
    运算符

    编辑: 将
    映射到concat每个值的示例:

    constfoo$=of('foo').pipe(filter(()=>false));
    const bar$=of('bar').pipe(过滤器(()=>false));
    const baz$=of('baz').pipe(过滤器(()=>false));
    
    merge(foo$、bar$、baz$).pipe(map(v=>`>>>${v}实现这一点的一种方法是使用对:

    source$.pipe(
    //将流上的所有事件转换为通知
    具体化(),
    //仅当元素存在时才换行
    开关映射((事件、索引)=>{
    //如果它的第一个事件和一个值
    如果(索引===0&&event.kind==='N'){
    const startingNotification=新通知('N','>>>',未定义);
    返回(启动通知、事件);
    }
    //如果它是一个完成事件而不是第一个事件
    如果(索引>0&&event.kind=='C'){
    
    const endingNotification=new Notification('N','第一个条件很简单。您只需使用
    concatMap
    预先设置第一个发射:

    mergeMap((v, index) => index === 0 ? of('>>>', v) : of(v))
    
    第二个条件更为棘手。您基本上想要的是与
    defaultIfEmpty
    相反的右键。我想不出任何简单的解决方案,因此我可能会使用
    endWith
    ,如果它是第一个也是唯一的发射,则忽略发射(这意味着源刚刚完成,没有发射任何东西):

    endWith('>>,v):of(v)),
    
    endWith(“您可以将合并的可观察对象分配给一个变量,从流中获取第一个元素,然后映射到至少发出一个值时要执行的可观察对象

    const foo$=of('foo').pipe(过滤器(()=>false))
    常量条$=的('bar')。管道(过滤器(()=>false))
    const baz$=of('baz').pipe(过滤器(()=>false))
    const merged$=合并(foo$、bar$、baz$);
    合并的$管道(
    以(1)为例,
    switchMap(()=>合并的$.pipe(
    startWith('>>'),
    
    结束(“我知道所有答案都是通过组合运算符来完成的,但是只使用运算符来解决这个问题有点棘手,为什么不创建自己的可观察的运算符呢?我认为这个解决方案是最容易理解的。没有隐藏的聪明,没有复杂的运算符组合,没有子运算符描述重复

    解决方案:

    constfoo$=of('foo')/.pipe(filter(()=>false));
    const bar$=of('bar')/.pipe(过滤器(()=>false));
    const baz$=of('baz')/.pipe(过滤器(()=>false));
    函数wrapIfOnEmit$(…obs){
    返回新的可观察对象(观察者=>{
    让我来;
    常量订阅=合并(…obs)。订阅((数据)=>{
    如果(!hasEmission){
    观察者。下一个('>>');
    a=真;
    }
    下一步(数据);
    },
    (错误)=>观察者错误(错误),
    () => {
    
    if(hasEmissed)observer.next('我的预期输出是if
    merge()
    不发出值,那么我就不应该看到
    >
    也不应该看到
    我有一个可能产生值或可能不产生值的流。当流完成时,我需要连接发出的字符串,然后才应用前缀/后缀。我可以在管道外部应用我的词缀,但我想知道是否可以将这种行为添加到其中。希望是澄清了一点。@customcommander我添加了一个示例,希望这就是您想要的。谢谢,但这不会将词缀应用于每个发出的值吗?我需要发出
    >
    ,并且
    我可以看到混淆,我已经编辑了我的问题。对不起。我想,另一种方法是将
    throwIfEmpty
    startWith一起使用
    endWith
    ,然后是
    catchError
    ,这将抑制“空错误”并通过原始错误。但需要测试此方法。谢谢您的回答。当
    合并的$
    完全不发射时,此方法有效。否则,如果其中一个合并的可观察对象发射值,则无论是
    开始时间
    还是
    结束时间
    都不会发射其值。@customcommander否,只要其中一个合并的可观察对象发射值发出一个值,您正在将该值映射到另一个流,该流使用
    startWith
    endWith
    发出。请查看我的堆栈闪电并删除
    .pipe(过滤器(()=>false))
    对于其中一个观测值。抱歉。我确实尝试过,但它不起作用,但当我从您的答案中重写代码时,我一定是在某个地方打错了。我复制/粘贴了您的代码,它就起作用了;)我非常喜欢这个答案。我将等待更多的答案(@customcommander,fridoo,这导致了对
    合并$
    的双重订阅。因此,需要在
    switchMap
    @kos内部执行
    concat
    。我的理解是
    switchMap
    将从可观察的源取消订阅。因此,除非我弄错了,否则应该没问题。谢谢你。我感觉来自@fridoo的答案更为惯用。+1思想请注意,对于第一次发射可能被吞没的“热”观测,该解决方案可能会产生不同的结果。我猜您可以将第一次发射添加到
    startWith<
    
    endWith('<<<'),
    filter((v, index) => index !== 0 || v !== '<<<'),
    
    const foo$ = of('foo');//.pipe(filter(() => false));
    const bar$ = of('bar');//).pipe(filter(() => false));
    const baz$ = of('baz');//.pipe(filter(() => false));
    
    merge(foo$, bar$, baz$).pipe(
      mergeMap((v, index) => index === 0 ? of('>>>', v) : of(v)),
      endWith('<<<'),
      filter((v, index) => index !== 0 || v !== '<<<'),
    ).subscribe(console.log);