原文链接:RxJS: Avoiding takeUntil Leaks
原文作者:Nicholas Jamieson;发表于2018年5月27日
译者:yk;如需转载,请注明出处,谢谢合作!

摄影:Tim Gouw,来自 Unsplash

使用 takeUntil 操作符来实现 observable 的自动取消订阅是 Ben Lesh 在 Don’t Unsubscribe 中所提出的一种机制。

译者注:《Don’t Unsubscribe》在 RxJS 中文社区中已有相应译文,有兴趣可以看看。

而该机制也是 Angular 中组件销毁所采用的取消订阅模式的基础。

为了使该机制生效,我们必须以特定的顺序调用操作符。而我最近却发现有些人在使用 takeUntil 时,会因为操作符调用顺序的问题而导致订阅泄露。

让我们来看看哪些调用顺序是有问题的,以及导致泄露的原因。

哪些调用顺序是有问题的?

如果在 takeUntil 后面调用这样一个操作符,该操作符订阅了另一个 observable,那么当 takeUntil 收到通知时,该订阅可能不会被取消。

举个例子,这里的 combineLatest 可能会泄露 b 的订阅。

import { Observable } from "rxjs";
import { combineLatest, takeUntil } from "rxjs/operators";declare const a: Observable<number>;
declare const b: Observable<number>;
declare const notifier: Observable<any>;const c = a.pipe(takeUntil(notifier),combineLatest(b)
).subscribe(value => console.log(value));
复制代码

同样,这里的 switchMap 也可能会泄露 b 的订阅。

import { Observable } from "rxjs";
import { switchMap, takeUntil } from "rxjs/operators";declare const a: Observable<number>;
declare const b: Observable<number>;
declare const notifier: Observable<any>;const c = a.pipe(takeUntil(notifier),switchMap(_ => b)
).subscribe(value => console.log(value));
复制代码

为什么会导致泄露?

当我们用 combineLatest 静态工厂函数来代替已废弃的 combineLatest 操作符时,泄露的原因会更加明显,请看代码:

import { combineLatest, Observable } from "rxjs";
import { takeUntil } from "rxjs/operators";declare const a: Observable<number>;
declare const b: Observable<number>;
declare const notifier: Observable<any>;const c = a.pipe(takeUntil(notifier),o => combineLatest(o, b)
).subscribe(value => console.log(value));
复制代码

notifier 发出时,由 takeUntil 操作符返回的 observable 就算完成了,其订阅也会被自动取消。

然而,由于 c 的订阅者所订阅的 observable 并非由 takeUntil 返回,而是由 combineLatest 返回,所以当 takeUntil 的 observable 完成时,c 的订阅是不会被自动取消的。

combinedLast 的所有 observable 全部完成之前,c 的订阅者都将始终保持订阅。所以,除非 b 率先完成,否则它的订阅就会被泄露。

要想避免这个问题,我们就得把 takeUntil 放到最后调用:

import { combineLatest, Observable } from "rxjs";
import { takeUntil } from "rxjs/operators";declare const a: Observable<number>;
declare const b: Observable<number>;
declare const notifier: Observable<any>;const c = a.pipe(o => combineLatest(o, b),takeUntil(notifier)
).subscribe(value => console.log(value));
复制代码

如此一来,当 notifier 发出时,c 的订阅就会被自动取消。因为当 takeUntil 中的 observable 完成时,takeUntil 会取消 combineLatest 的订阅,这样也就依次取消了 ab 的订阅。

使用 TSLint 来避免这个问题

如果你正在使用 takeUntil 的机制来实现间接地取消订阅,那么你可以通过启用我添加到 rxjs-tslint-rules 包里的 rxjs-no-unsafe-takeuntil 规则来确保 takeUntilpipe 中的最后一个操作符。


更新

通常的规定是将 takeUntil 放到最后。然而在有些情况下,你可能需要把它放到倒数第二个的位置上。

在 RxJS 的操作符中,有一些是只在源 observable 完成时才会发出值的。就比如说 counttoArray,只有在它们的源 observable 完成时,它们才会发出源 observable 中数据的个数,或是其组成的数组。

当一个 observable 因 takeUntil 而完成时,类似 counttoArray 的操作符只有放在 takeUntil 后面才会生效。

另外还有一个操作符是你需要放在 takeUntil 后面的,那就是 shareReplay

目前的 shareReplay 有一个 bug/feature:它永远不会取消其源 observable 的订阅,直到源 observable 完成,或是发生错误,详见 PR。所以将 takeUntil 放在 shareReplay 后面是无效的。

上面提到的 TSLint 规则是知道这些例外的,所以你不用担心会造成一些莫名其妙的问题。


在 6.4.0 版本的 RxJS 中,shareReplay 做了一定修改,现在你可以通过 config 参数来指定其引用计数行为。如果你指定了 shareReplay 的引用计数,就可以把它安全地放到 takeUntil 前面了。

想了解更多有关 shareReplay 的信息,请看这篇文章。

转载于:https://juejin.im/post/5cb89a786fb9a0685f3de14d

[译] RxJS: 避免 takeUntil 造成的泄露风险相关推荐

  1. fastjson反序列化漏洞_漏洞预警Fastjson再爆反序列化代码执行漏洞;星巴克被发现存在信息泄露风险...

    漏洞预警 Fastjson再次爆出通杀的反序列化代码执行漏洞 漏洞信息 据态势感知平台监测,网络上再次出现此前未曾发现的fastjson反序列化攻击向量. Fastjson是由阿里巴巴推出基于Java ...

  2. 无线网络现漏洞 信息泄露风险大增

    本文讲的是 :   无线网络现漏洞 信息泄露风险大增 , [IT168资讯]近日,深圳两家国内市场主流的无线设备厂家被曝所生产的某些型号及批次的无线路由器存在WPS(Wi-Fi Protected S ...

  3. [译]RxJS文档04——Observer 观察者

    原文: http://reactivex.io/rxjs/manu... 什么是Observer? 观察者(Observer)是Observable流推送数据的用户.观察者们(Observers)就是 ...

  4. 【译】Activitys, Threads和 内存泄露

    Android编程中一个共同的困难就是协调Activity的生命周期和长时间运行的任务(task),并且要避免可能的内存泄露.思考下面Activity的代码,在它启动的时候开启一个线程并循环执行任务. ...

  5. 【译】什么导致了Context泄露:Handler内部类

    思考下面代码 1 public class SampleActivity extends Activity { 2 3 private final Handler mLeakyHandler = ne ...

  6. Java中七个潜在的内存泄露风险,你知道几个?

    虽然Java程序员不用像C/C++程序员那样时刻关注内存的使用情况,JVM会帮我们处理好这些,但并不是说有了GC就可以高枕无忧,内存泄露相关的问题一般在测试的时候很难发现,一旦上线流量起来可能马上就是 ...

  7. Java 中 7 个潜在的内存泄露风险

    虽然Java程序员不用像C/C++程序员那样时刻关注内存的使用情况,JVM会帮我们处理好这些,但并不是说有了GC就可以高枕无忧,内存泄露相关的问题一般在测试的时候很难发现,一旦上线流量起来可能马上就是 ...

  8. 实名认证需谨慎,避免陷入隐私泄露风险

    今天,炒鸡辣鸡看见了去转盘网在知乎对网盘爬虫进行了分析(https://zhuanlan.zhihu.com/p/24647100),文章里面提到了有一种方案是调用别人的接口来实现. 要知道,炒鸡辣鸡 ...

  9. 长城宽带核心系统存严重漏洞,数十万用户、账单信息存泄露风险

    在网上搜到一处 鹏博士oa的入口: http://124.207.189.73/defaultroot/login.jsp 随即猜测口令 test test123 注意在IE下使用 成功登陆其oa系统 ...

最新文章

  1. BZOJ1702: [Usaco2007 Mar]Gold Balanced Lineup 平衡的队列
  2. 《数据结构与算法分析:C语言描述》复习——第六章“排序”——基数排序
  3. qt框架的开发模式_Flutter 混合开发框架模式探索
  4. 配置spring整合jpa自动生成数据表
  5. 逆向工程核心原理学习笔记(九):小端序标记法2
  6. java中解决脏读_多线程出现脏读以及解决方法(使用synchronized)
  7. 【Java】Java反射机制重点总结
  8. Flutter Icons 与 CupertinoIcons 的不一样的体验
  9. 电脑排行榜笔记本_2019联想笔记本电脑排行榜
  10. 20190916:(leetcode习题) 二叉树的层次遍历
  11. 如何将网页实现变灰效果?
  12. 双向链表与LinkedHashMap
  13. Mnist数据集介绍
  14. bin文件的安装方法
  15. 两向量叉乘的计算公式_向量的叉乘运算法则
  16. 强大实用的win10任务栏创建分组菜单工具
  17. Apple Pay正式入华:能否成支付宝与微信强敌
  18. CSS 单词换行 word-break属性
  19. 单例模式、适配器模式
  20. 我的图床解决方案,超详细!

热门文章

  1. 序列拼接工具Bowtie使用说明
  2. CNN网络优化加速开源代码汇总
  3. ASP .NET Core Web Razor Pages系列教程四:使用数据库进行交互 entity-framework(MySQL/MariaDB 版)
  4. Python中bitmap数据结构的构造和使用
  5. linux mysql删除root_Linux下误删MySQL的root用户解决方法
  6. MySQL存储过程详解
  7. mac上的终端bash命令
  8. 海王必备,我用python写了一个微信机器人和她聊天之后把我拉黑了
  9. oracle sap 用友 保险财务系统比较,SAP和用友的财务管理系统比较详解
  10. Linux进程及进程管理命令