【问题标题】:how switch operator unsubscribing the previous observables?切换操作员如何取消订阅以前的 observables?
【发布时间】:2019-03-23 05:06:12
【问题描述】:

我正在尝试理解 observables。 当我使用 switch 运算符时,我无法理解“它取消订阅以前的 observable 并订阅新的”这一行

var inp=document.getElementById("i");
var t=Rx.Observable.fromEvent(inp,"keyup");
t.map((e)=>Rx.Observable.range(1,3)).subscribe((e)=>console.log(e))
///t.map((e)=>Rx.Observable.range(1,3)).switch().subscribe((e)=>console.log(e))

每当我在输入框中按任意键时,我都会在没有切换运算符的情况下得到这个输出:

RangeObservable {start: 1, rangeCount: 3, scheduler: CurrentThreadScheduler}
rangeCount: 3
scheduler: CurrentThreadScheduler {}
start: 1
__proto__: ObservableBase

但是当我在 map 运算符之后使用 switch 运算符时,输出变为1,2,3。 switch 操作符在内部做什么?

【问题讨论】:

    标签: javascript asynchronous rxjs reactive-programming


    【解决方案1】:

    当您在执行t.map((e)=>Rx.Observable.range(1,3)) 时,t 本身是来自输入事件的 Observable,然后您从那里将其映射到 嵌套 Observable 的 Observable,它将发出从 1 到 3 的整数.

    现在你对它应用switch 操作符,它本质上作用于Observable 的Observable。在您的情况下,t.map(..) 正在通过在内部调用 Rx.Observable.range(1,3) 创建内部 Observable 的 Observable。

    因此,一旦从 Rx.Observable.range(1,3) 发出 Observable,switch 运算符将取消订阅来自 t.map(...) 调用的 Observable,并订阅 Rx.Observable.range(1,3) 调用的最新 Observable。

    按照switch运算符的documentation,请注意最新这个词:

    Switch 订阅了一个发出 Observable 的 Observable。每一次 它观察这些发出的 Observable 之一,返回的 Observable 通过 Switch 取消订阅之前发出的 Observable 开始 从最新的 Observable 发射项目。

    要将您的代码更改为不使用switch,您需要通过t.map(...) 调用订阅嵌套的Observable:

    t.map((e)=>Rx.Observable.range(1,3)).subscribe((e)=> e.subscribe(e => console.log(e)))
    

    这将在控制台中输出1, 2, 3。所以switch 使它更优雅,而不是订阅嵌套的 Observable,您只需 switch 在它发出后立即切换到它。

    t.map((e)=>Rx.Observable.range(1,3)).switch().subscribe((e)=>console.log(e))
                           //  ^
                           //  |_________________ now this Observable is subscribed as soon as it is emitted.
    

    这是一个演示,说明如何在没有switch 的情况下订阅内部 Observable 以获取 1、2、3:

    var inp=document.getElementById("input");
    var t=Rx.Observable.fromEvent(inp,"keyup");
    console.log("** Without Switch ***")
    t.map((e)=>Rx.Observable.range(1,3)).subscribe((e)=> e.subscribe(e => console.log(e)));
    <script src="https://npmcdn.com/@reactivex/rxjs@5.0.0-beta.6/dist/global/Rx.umd.js"></script>
    Enter something: <input type="text" id='input'>

    这里和switch一样:

    var inp=document.getElementById("input");
    var t=Rx.Observable.fromEvent(inp,"keyup");
    console.log("** With Switch ***")
    t.map((e)=>Rx.Observable.range(1,3)).switch().subscribe(e=> console.log(e));
    <script src="https://npmcdn.com/@reactivex/rxjs@5.0.0-beta.6/dist/global/Rx.umd.js"></script>
    Enter something: <input type="text" id='input'>

    【讨论】:

    • 这是我无法想象的地方......可观察的可观察的并取消订阅前一个并订阅最新的。" Switch 返回的 Observable 取消订阅先前发出的 Observable "..这些语句不清楚
    • 所以t.map((e)=&gt;Rx.Observable.range(1,3))调用是一个带有嵌套Observable的Observable,现在如果你直接订阅它,你将得到一个包含另一个Observable对象的Observable对象,如你的输出所示,但你没有'不想要那个,你想要1, 2, 3 所以你需要订阅嵌套的 Observable 来获得那个输出。所以switch很容易。您只需 切换 到嵌套的 Observable 并订阅它并取消订阅父 Observable,而不是再次订阅。
    • 谢谢,我明白了。这是否意味着 switch 运算符只能用于嵌套的 observables 并且每个运算符都会在每次 source observable 发出值时创建中间 observable?
    • 是的 switch 就是这样工作的,但并不是每个操作员都会创建中间 Observable。在您的示例中,您通过映射到嵌套的 Observable 来明确地做到这一点。如果没有Rx.Observable.range(1,3),你只会得到一个包裹在 Observable 中的键盘事件。如果有帮助,请不要忘记接受我的回答!
    猜你喜欢
    • 2021-03-13
    • 2017-03-26
    • 2020-10-28
    • 2017-08-24
    • 2019-04-21
    • 1970-01-01
    • 2017-12-17
    • 2013-04-16
    • 2023-03-23
    相关资源
    最近更新 更多