当最后一个观察者取消订阅时如何防止 AsyncSubject 完成

2023-12-20

The AsyncSubject当最后一个主题观察者取消订阅该主题时,该主题变得可观察。这是报价单 https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339#2991:

当它完成时,它就完成了。对象在使用后无法重复使用 取消订阅、已完成或有错误。

这是演示:

const ofObservable = Rx.Observable.of(1, 2, 3);
const subject = new Rx.AsyncSubject();

ofObservable.subscribe(subject);

subject.subscribe((v) => {
    console.log(v);
});

subject.unsubscribe((v) => {
    console.log(v);
});

// here I'll get the error "object unsubscribed"
subject.subscribe((v) => {
    console.log(v);
});

如何阻止主题完成?

有一个share操作员:

在 RxJS 5 中,运算符share()制作一个热的、refCounted 的 observable 失败时可以重试,成功时可以重复。因为 一旦出现错误、完成或其他情况,主题就无法重复使用 取消订阅,则share() 操作员将把死去的受试者回收到 启用重新订阅到结果可观察值。

这就是我正在寻找的。但share创建一个主题,我需要AsyncSubject.


问题归结为这一行:

subject.unsubscribe((v) => {
    console.log(v);
});

Subject 实施ISubscription https://github.com/ReactiveX/rxjs/blob/5.4.2/src/Subject.ts#L22;这意味着它有一个unsubscribe方法和一个closed财产。它是实施unsubscribe https://github.com/ReactiveX/rxjs/blob/5.4.2/src/Subject.ts#L96-L100如下:

unsubscribe() {
  this.isStopped = true;
  this.closed = true;
  this.observers = null;
}

这有点残酷。本质上,它会切断与该主题的任何订阅者的所有通信,而无需取消订阅。同样,它不会从它可能碰巧订阅的任何可观察对象中取消订阅主题本身。 (它还将主题标记为关闭/停止,这就是您错误的原因。)

鉴于它实际上并不执行任何取消订阅,因此尚不清楚它应该如何使用。的描述这次测试 https://github.com/ReactiveX/rxjs/blob/5.4.2/spec/Subject-spec.ts#L235-L276:

it('should disallow new subscriber once subject has been disposed', () => {

表明这可能是 RxJS 4 的某种后遗症 - 其中取消订阅被称为处置。

无论其存在的原因是什么,我建议永远不要调用它。举例来说,看看这个片段:

const source = Rx.Observable
  .interval(200)
  .take(5)
  .do(value => console.log(`source: ${value}`));

const subject = new Rx.Subject();
source.subscribe(subject);

const subscription = subject
  .switchMap(() => Rx.Observable
    .interval(200)
    .take(5)
    .delay(500))
  .subscribe(value => console.log(`subscription: ${value}`));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>

它将主题订阅到源可观察量,然后订阅由该主题组成的可观察量。

If unsubscribe当这个主题被调用时,一些问题就变得明显了:

  • 主题对源的订阅并未取消订阅,并且当源尝试调用主题的next方法;和
  • 对由主题组成的可观察量的订阅不会取消订阅,因此interval内可观察到switchMap后继续发光unsubscribe已拨打电话。

试试看:

const source = Rx.Observable
  .interval(200)
  .take(5)
  .do(value => console.log(`source: ${value}`));

const subject = new Rx.Subject();
source.subscribe(subject);

const subscription = subject
  .switchMap(() => Rx.Observable
    .interval(200)
    .take(5)
    .delay(500))
  .subscribe(value => console.log(`subscription: ${value}`));

setTimeout(() => {
  console.log("subject.unsubscribe()");
  subject.unsubscribe();
}, 700);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>

这些似乎都不是理想的行为,所以打电话unsubscribe on a Subject是应该避免的事情。

相反,您的代码片段中的代码应该使用以下方式取消订阅Subscription由返回subscribe call:

const subscription = subject.subscribe((v) => {
  console.log(v);
});
subscription.unsubscribe();

写完这个答案后,我发现了以下评论 https://medium.com/@benlesh/on-the-subject-of-subjects-in-rxjs-2b08b7198b93 from Ben Lesh http://stackoverflow.com/users/135786,这符合我的理论,即它与主题的处理有关:

如果你想让对象在你说话时大声而愤怒地犯错next当它有用后,你可以调用unsubscribe直接作用于主题实例本身。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当最后一个观察者取消订阅时如何防止 AsyncSubject 完成 的相关文章

  • 在 Three.js 中绕点旋转对象的正确方法是什么?

    关于 Three js 的大多数教程 问题都建议使用 Three js 绕点旋转对象的方法是在要旋转的位置创建父对象 附加对象 然后移动子对象 然后 当父级旋转时 子级围绕该点旋转 例如 Make a pivot var pivot new
  • Jquery 悬停卡

    我在用着http designwithpc com Plugins Hovercard http designwithpc com Plugins Hovercard 但我不知道如何在悬停卡上声明 var 每个工作描述都有自己的 ID 当悬
  • Firebase,只得到新的孩子[重复]

    这个问题在这里已经有答案了 var firebase new Firebase firebaseRef on child added function snapshot 这将接收所有元素 有没有办法在创建新的 Firebase 引用时不接收
  • 从函数返回函数的目的是什么?

    阅读一些遗留代码 发现 A prototype setSize function var v1 new Vector2 return function size var halfSize v1 copy size multiplyScala
  • 如何正确清理来自 AngularJS 控制器的无效输入的表单?

    我有一个 AngularJS 表单 其中包含 除其他字段之外 类型之一url 后者很重要 因为这会强制相应的输入成为有效的 URL 在某些条件下 例如 要关闭具有此类表单的模式对话框 我想以编程方式清除该表单 为此 我实现了方法reset基
  • jQuery .push 到 .get 调用中的数组给出空结果

    谁能告诉我为什么下面给我一个空字符串 当我console log contentArray in the get 回调函数它显示数据 但是当我尝试在下面的代码中执行它时 结果为空 sectionArray contentArray func
  • 如何使用javascript确保元素仅在圆上朝一个方向移动?

    好吧 我承认我对三角学真的很糟糕 出于上下文的考虑 我将添加我在这里提到的问题中的内容 参考问题 https stackoverflow com a 39429290 168492 https stackoverflow com a 394
  • 如何在网站上使用 svg 元素制作块的屏幕截图?

    我在网站上创建了一个构造函数 其本质是将所选元素及其颜色 svg中的元素 添加到访问者选择的背景和背景颜色 png中的背景 中 然后必须单击 保存 结果 按钮并仅执行工作区的屏幕截图 我写了这个脚本 但它需要屏幕截图 但只有背景 并忽略选定
  • IntersectionObserver是否支持水平滚动观察?

    我制作了几个垂直滚动 IntersectionObserver 模块 但我对水平滚动感兴趣 根将是 div 观察目标将是 img 我想观察当 img 放大但 div 保持视口宽度时的变化 我什至不确定移动 Safari 是否会将缩放后的图片
  • 导航栏下拉菜单(折叠)在 Bootstrap 5 中不起作用

    我在尝试使用以下命令创建响应式菜单或下拉按钮时遇到问题Bootstrap 5一切似乎都正常 导航图标和下拉图标出现 但它不起作用 当我单击nav图标或dropdown按钮 无dropdown menu apears 我想特别提到的是 我还包
  • JavaScript 继承;调用和原型

    要在Javascript中实现继承 通常需要执行以下两个步骤 假设我有一个基类 Animal var Animal function name this name name 我现在想从中派生一个子类 Dog 所以我想说 var Dog fu
  • 将 Firebase 云消息传递与 Windows 应用程序结合使用

    我在 Android 和 iOS 应用程序中使用 Firebase Cloud Messaging 但是我还有此应用程序的 Windows Mac OS 版本 我想保留相同的逻辑 我知道 Firebase Cloud Messaging 可
  • mongodb 聚合 - 累积字段的不同组值

    如果我有Player表格文件 name String score Int 我有Group文档 其中组代表玩家列表 groupName String players ObjectID 玩家可以属于多个组 我想做一个聚合Player文档 按以下
  • 改变 JavaScript 中的顶部填充

    以下是我在 css 中设置顶部填充的方法 body font size font size px margin 0 padding 100px 0 20px 0 width 100 important 如何使用最简单的 javascript
  • 用于选择特定 div 中具有特定类的锚元素的 jQuery 选择器是什么

    我有一些这样的代码 我想选择每个 a 带有类的标签status在 div 中foo div a class status a div 你可以这样做 foo find status a
  • 订阅内循环订阅?

    我目前正在与订阅内的 multiples forEach 订阅作斗争 我正在尝试检索对象列表 然后通过它们的 ID 检索它们的图像 目前我已经这样做了 this appTypeService get pipe map apps AppTyp
  • 使用 next.js 进行服务器端渲染与传统 SSR

    我非常习惯 SSR 意味着页面得到完全刷新并从服务器接收完整 HTML 的方法 其中根据后端堆栈使用 razor pub other 进行渲染 因此 每次用户单击导航链接时 它只会向服务器发送请求 整个页面将刷新 接收新的 HTML 这就是
  • 使用 Enzyme 测试 `React.createRef` api

    我想测试下面的类 它使用React createRef api 不过 快速搜索并没有发现任何这样做的例子 有人成功过吗 我该如何嘲笑裁判 理想情况下我想使用shallow class Main extends React Component
  • 在 iOS 7 Safari 中,如何区分通过边缘滑动与后退/前进按钮的 popstate 事件?

    在 iOS 7 Safari 中 现在有两种后退 前进导航方式 使用底部的传统后退 前进按钮箭头或从屏幕边缘滑动 我正在使用动画在 ajax 应用程序中的页面之间进行转换 但如果用户通过边缘滑动进行导航 我不想触发该转换 因为这本身就是一个
  • 将数组从 jquery ajax 传递到代码后面

    我必须将二维数组传递给在asp net网页代码后面编写的页面方法我有一个变量objList作为二维数组 我使用以下代码来实现此目的 但没有成功 并且未调用页面方法 脚本语言 function BindTable objList ajax u

随机推荐