Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
rxjs switchMap需要返回订阅的可观测数据_Rxjs_Observable - Fatal编程技术网

rxjs switchMap需要返回订阅的可观测数据

rxjs switchMap需要返回订阅的可观测数据,rxjs,observable,Rxjs,Observable,以下是要求: 单击开始按钮时,每100ms发射事件x次,每次发射对应一次UI更新。当x次发射完成时,它将触发最终的UI更新,看起来很简单吧 这是我的密码: const start$ = fromEvent(document.getElementById('start'), 'click') const intervel$ = interval(100) .pipe( take(x), share() ) var startLight$ = star

以下是要求:

单击开始按钮时,每100ms发射事件x次,每次发射对应一次UI更新。当x次发射完成时,它将触发最终的UI更新,看起来很简单吧

这是我的密码:

const start$ = fromEvent(document.getElementById('start'), 'click')
const intervel$ = interval(100)
    .pipe(
        take(x),
        share()
    )
var startLight$ = start$
    .pipe(
        switchMap(() => {
            intervel$
                .pipe(last())
                .subscribe(() => {
                    // Update UI
                })
            return intervel$
        }),
        share()
    )
startLight$
    .subscribe(function (e) {
        //Update UI
    })
显然,subscribe inside
switchMap
是反模式的,所以我尝试重构代码:

const startInterval$ = start$
    .pipe(
        switchMapTo(intervel$),
    )
startInterval$.pipe(last())
    .subscribe(() => {
        //NEVER Receive value
    })

const startLight$ = startInterval$.pipe(share()) 
问题是intervel$流是在
switchMap
内部生成的,不能在外部访问,您只能访问生成interval$的流,即start$,它永远不会完成


是否有更聪明的方法来处理此类问题,或者这是
rxjs
的固有限制?

将更新逻辑放入
开关映射中
tap()
,tap将运行多次,subscribe()只执行最后一次发射


你很接近。在intervel$中使用last()只向下面的订阅发送最后一个。工作以下是StackBlitz的详细信息:

const start$ = fromEvent(document.getElementById('start'), 'click');
const intervel$ = interval(100)
    .pipe(
        tap(() => console.log('update UI')), // Update UI here
        take(x),
        last()
    );

const startInterval$ = start$
    .pipe( switchMapTo(intervel$));

startInterval$
    .subscribe(() => {
        console.log('will run once');
    });
更新 如果您不希望使用
tap()
,那么您可以通过仅获取第一次发射,然后使用
take(1)
first()
完成,从而使start$完成。展示这个

const start$ = fromEvent(document.getElementById('start'), 'click')
    .pipe(
      first()
    );
const intervel$ = interval(100)
    .pipe( 
      take(x) 
    );

const startInterval$ = start$
    .pipe( 
      switchMapTo(intervel$)
    );

startInterval$
    .subscribe(
      () => console.log('Update UI'),
      err => console.log('Error ', err),
      () => console.log('Run once at the end')
    );
这种方法(或完成可观察对象的任何方法)的缺点是,一旦完成,它就不会被重用。例如,在新的StackBlitz中多次单击按钮将不起作用。使用哪种方法(第一种可以反复点击的方法或完成的方法)取决于您需要的结果

另一种选择 创建两个
intervel$
可观察对象,一个用于中间用户界面更新,另一个用于最终用户界面更新。将它们合并在一起,只在订阅中更新UI。对于此选项

代码:

一种更惯用的方式,与前一种逻辑相同(Guichi) 反射
原始问题的关键问题是“以不同的方式使用相同的观察值”,即在进度和最终阶段。因此,
merge
是针对此类问题的一种相当不错的逻辑模式

@Fan Cheung谢谢你们两位,你们基本上提供了保存解决方案!他们肯定很有帮助。然而,有人认为“将重要的副作用从do移到subscribe”[,这是一个不错的建议还是可以实现的方法?而且,我认为
subject
可以解决这个问题。但是
subject
让我感到陌生。只是一个模糊的想法,它可能会起作用。有可能充实吗?我很少在subscribe()中添加任何内容,因为流应该是可重用的、可组合的。在开发功能时,大多数时候你需要改进和重构流的片段,如果你想要额外的逻辑,只需链接和扩展流,并将其另存为另一个流。@Guichi-我在上面添加了一个更新,其中包含一个替代解决方案,可观察的完成。是的,正如我所提到的,这是完成一个可观察的界面的缺点。好的,我的最后一个想法如下:创建两个intervel,一个用于中间UI更新,一个用于最终UI更新。将它们合并在一起,并仅在订阅中更新UI,不点击:
const start$ = fromEvent(document.getElementById('start'), 'click')
    .pipe(
      first()
    );
const intervel$ = interval(100)
    .pipe( 
      take(x) 
    );

const startInterval$ = start$
    .pipe( 
      switchMapTo(intervel$)
    );

startInterval$
    .subscribe(
      () => console.log('Update UI'),
      err => console.log('Error ', err),
      () => console.log('Run once at the end')
    );
const start$ = fromEvent(document.getElementById('start'), 'click')
const intervel1$ = interval(100)
    .pipe( 
      take(x)
    );
const intervel2$ = interval(100)
    .pipe(
      take(x+1),
      last(),
      mapTo('Final')
    );

const startInterval$ = start$
    .pipe( 
      switchMapTo(merge(intervel1$, intervel2$))
    );

startInterval$
    .subscribe(
        val => console.log('Update UI: ', val)
    );
import { switchMapTo, tap, take, last, share, mapTo } from 'rxjs/operators';
import { fromEvent, interval, merge } from 'rxjs';

const x = 5;

const start$ = fromEvent(document.getElementById('start'), 'click');


const intervel$ = interval(100);

const intervel1$ = intervel$
  .pipe(
    take(x)
  );
const intervel2$ = intervel1$
  .pipe(
    last(),
    mapTo('Final')
  );

const startInterval$ = start$
  .pipe(
    switchMapTo(merge(intervel1$, intervel2$))
  );

startInterval$
  .subscribe(
    val => console.log('Update UI: ', val)
  );