RxJS技术问询:switchMap在false条件下是否取消订阅Subject?为何值重置?
问题描述
我有以下几个关于RxJS代码输出的疑问:
- 为何输出的计数会重新从0开始,而非延续之前的计数?
- switchMap在false条件下是否会取消订阅Subject?
- 为何timer的值会重新初始化?
相关代码
const { Subject, interval } = require('rxjs'); const { switchMap, filter,tap } = require('rxjs/operators'); // 每秒发射一次的计时器Observable const timer$ = interval(1000) // 用作开关的Subject const switch$ = new Subject(); // 仅在开关开启时发射计时器数据 const subscription = switch$.pipe( filter(toggle => toggle), switchMap(toggle => timer$) ).subscribe(time => console.log('ms passed: ' + time)) // 模拟开关操作 setTimeout(() => switch$.next(true), 1000); setTimeout(() => switch$.next(false), 4000); setTimeout(() => console.log('-------'), 5500); setTimeout(() => switch$.next(true), 6000); setTimeout(() => switch$.next(false), 7000); setTimeout(() => subscription.unsubscribe(), 10000);
输出结果
ms passed: 0
ms passed: 1
ms passed: 2
ms passed: 3ms passed: 0
ms passed: 1
ms passed: 2
解答
1. 计数重新从0开始的原因
你定义的timer$是interval(1000),这个Observable的特性是:每次被订阅时,都会启动一个全新的计时周期,从0开始计数。
第一次switch$.next(true)触发时,filter通过该值,switchMap会订阅timer$的第一个实例,开始从0输出计数;当6000ms时再次switch$.next(true),switchMap会先取消之前订阅的timer$实例,然后订阅一个全新的timer$实例,自然会重新从0开始计数。
2. switchMap在false条件下是否会取消订阅Subject?
首先,filter(toggle => toggle)会直接过滤掉false值,所以当switch$.next(false)时,这个值根本不会传递到switchMap操作符,switchMap不会对此做出任何反应。
另外,switch$的订阅是绑定在整个subscription上的,只有当你调用subscription.unsubscribe()时,才会取消对switch$的订阅。switchMap仅负责管理其内部订阅的Observable(也就是timer$),不会影响对上游switch$的订阅状态。
3. 为何值会重新初始化?
本质原因和第一个问题一致:interval创建的Observable是冷Observable,冷Observable的特点是每次被订阅时都会从头开始执行。每次switchMap收到true值时,都会重新订阅timer$,触发新的计时周期,所以值会从0重新初始化。
内容的提问来源于stack exchange,提问作者Samarth Mishra

