RxJS Subject是什么,使用它们有哪些好处?

15
我发现rxJS文档将其定义为:

什么是Subject?RxJS Subject是一种特殊类型的Observable,允许将值广播到多个观察者。虽然普通的Observables是单播的(每个已订阅的观察者拥有Observable的独立执行),但Subjects是多播的。

它继续给出了示例,但我正在寻找一个基本的ELI5解释。据我理解,它有助于处理和定义序列中的项目。这正确吗?

我认为对我和其他人最有帮助的是看到一个简单的函数,有或没有定义rxJS Subject,以理解为什么它很重要?

谢谢!


你有使用rxjs Observable的经验吗? - Harry Ninh
从我的理解来看,它们有助于使事情异步化,并且它们与 promises 非常相似。 - garrettmac
http://xgrommx.github.io/rx-book/content/getting_started_with_rxjs/subjects.html - martin
4个回答

35

理解它最简单的方法是将一个 Subject 视为一个既是生产者又是消费者的角色。就像一个开放的通道,在其中某人可以在一端发送消息,任何订阅者都会在另一端接收到。

                                  +---------------
Sender                            | =>  =>  =>  =>  Subscriber
           -----------------------+   +----------- 
Message =>  =>  =>  =>  =>  =>  =>  =>  =>  =>  =>  Subscriber
           -----------------------+   +-----------
                                  | =>  =>  =>  =>  Subscriber
                                  +---------------
在代码术语中,假设你有一个主题的服务。
class MessageService {
  private _messages = new Subject<Message>();

  get messages: Observable<Message> {
    return this._messages.asObservable();
  }

  sendMessage(message: Message) {
    this._messages.next(message);
  }
}

注意 messages 属性返回的是一个 Observable 对象。这不是必需的。因为 Subject 已经是一个 Observable,任何人都可以直接订阅它。但我认为使用 asObservable 模式是为了限制用户对其的操作,即使用户只用它来订阅而不是发出信号。我们将发射事件保存在 sendMessage 方法中。

现在有了这个服务,我们可以将其注入到不同的组件中,这可以成为两个(或多个)任意组件进行通信(或只是接收任意事件通知)的一种方式。

class ComponentOne {
  constructor(private messages: MessageService) {}

  onClick() {
    this.messages.sendMessage(new Message(..));
  }
}

class ComponentTwo {
  constructor(private messages: MessageService) {}

  ngOnInit() {
    this.messages.messages.subscribe((message: Message) => {
      this.message = message;
    });
  }
}

Angular自己的EventEmitter实际上是一个Subject。当我们订阅EventEmitter时,我们订阅到了一个Subject,当我们对EventEmitter进行emit时,我们正在通过Subject向所有订阅者发送消息。

另请参见:


10

当你所编写的代码实际上是产生可观察数据的源头时,Subjects 是非常有用的。你可以轻松地让你的消费者订阅 Subject,然后调用 next() 函数将数据推入管道。

然而,如果你从其他来源获取数据并仅仅是传递它(可能首先进行转换),那么你最有可能要使用 此处 显示的其中一个创建运算符之一,例如 Rx.Observable.fromEvent 像这样

var clicks = Rx.Observable.fromEvent(document, 'click');
clicks.subscribe(x => console.log(x));

这使你能够保持在功能范式中,而使用Subject虽然有其用途,但有些人认为这是一种将命令式代码强制进入声明式框架的不良迹象。 这里有一个很好的答案,解释了这两种范式的区别。

4
如果你想要最简单的解释...
Observables通常是某些事物的结果。它们可以是一个http调用的结果,也可以是通过管道进行处理后的结果。
但是这些事物的来源是什么呢?你是否曾想过如何将用户事件与整个rxjs连接起来?Subject的主要特点是你可以在它们上面调用next()方法。
在进行响应式编程时,第一步通常是列出可能会有的subject列表。
例如:假设我们需要制作一个待办事项清单应用程序。我们可能会在组件中有几个变量:
public deleteItem$ = Subject<TodoItem> = new Subject();
public addItem$ = Subject<TodoItem> = new Subject();
public saveList$ = Subject<TodoItem[]> = new Subject();

在我们的应用程序中,我们将像这样连接它们:

<button (click)="deleteItem$.next(item)">Delete</button>

使用rxjs,我们将使用类似于merge/combineLatest/withLatestFrom的操作符来处理这些主题并定义我们的应用逻辑。
我会尽力找时间制作一个小例子。

1
你可以在这里找到有关主题语义的研究here
我看到的所有答案都是正确的。我只想补充一点,术语“subject”来自观察者模式(参见https://en.wikipedia.org/wiki/Observer_pattern)。因此,主题类似于一个继电器,它在一端接收某些内容,并在其任何端口(订阅)上发出它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接