Chủ đề so với Hành viSubject so với ReplaySubject trong Angular


122

Tôi đang tìm cách hiểu 3 điều đó:

Chủ đề , chủ đề Hành vichủ đề Phát lại . Tôi muốn sử dụng chúng và biết khi nào và tại sao, lợi ích của việc sử dụng chúng là gì và mặc dù tôi đã đọc tài liệu, xem hướng dẫn và tìm kiếm trên google, tôi vẫn không hiểu được điều này.

Vậy mục đích của họ là gì? Một trường hợp trong thế giới thực sẽ được đánh giá cao nhất, nó không cần phải viết mã.

Tôi muốn một lời giải thích rõ ràng không chỉ là "a + b => c mà bạn đã đăng ký ...."

Cảm ơn bạn


1
Đã có một câu hỏi với chủ đề hành vi có thể quan sát được; stackoverflow.com/questions/39494058/… và tài liệu về chủ đề phát lại rõ ràng imo github.com/Reactive-Extensions/RxJS/blob/master/doc/api/…
eko

Có một trình bày tương đối kỹ lưỡng về các chủ đề trong Rxjs trong câu trả lời này , bổ sung một cách độc đáo cho câu trả lời từ peeksilet. Điều này cũng bao gồm các chi tiết quan trọng về hành vi sau khi chấm dứt hợp đồng, vì vậy rất tốt để xem xét.
user3743222 Ngày

Câu trả lời:


277

Nó thực sự phụ thuộc vào hành vi và ngữ nghĩa. Với một

  • Subject- người đăng ký sẽ chỉ nhận được các giá trị đã xuất bản được phát ra sau khi đăng ký. Hãy tự hỏi bản thân, đó có phải là điều bạn muốn? Người đăng ký có cần biết gì về các giá trị trước đó không? Nếu không, thì bạn có thể sử dụng cái này, nếu không hãy chọn một trong những cái khác. Ví dụ, với giao tiếp thành phần với thành phần. Giả sử bạn có một thành phần xuất bản các sự kiện cho các thành phần khác khi nhấp vào nút. Bạn có thể sử dụng một dịch vụ với một đối tượng để giao tiếp.

  • BehaviorSubject- giá trị cuối cùng được lưu vào bộ nhớ đệm. Một người đăng ký sẽ nhận được giá trị mới nhất khi đăng ký ban đầu. Ngữ nghĩa của chủ đề này là đại diện cho một giá trị thay đổi theo thời gian. Ví dụ một người dùng đã đăng nhập. Người dùng ban đầu có thể là người dùng ẩn danh. Nhưng khi người dùng đăng nhập, thì giá trị mới là trạng thái người dùng được xác thực.

    Các BehaviorSubjectđược khởi tạo với giá trị ban đầu. Điều này đôi khi quan trọng đối với sở thích viết mã. Ví dụ, bạn khởi tạo nó bằng một null. Sau đó, trong đăng ký của bạn, bạn cần thực hiện kiểm tra vô hiệu. Có thể OK, hoặc có thể khó chịu.

  • ReplaySubject- nó có thể lưu vào bộ nhớ cache đến một số lượng khí thải xác định. Mọi người đăng ký sẽ nhận được tất cả các giá trị được lưu trong bộ nhớ cache khi đăng ký. Khi nào bạn cần hành vi này? Thành thật mà nói, tôi không có bất kỳ nhu cầu nào về hành vi đó, ngoại trừ trường hợp sau:

    Nếu bạn khởi tạo a ReplaySubjectvới kích thước bộ đệm là 1, thì nó thực sự hoạt động giống như a BehaviorSubject. Giá trị cuối cùng luôn được lưu trong bộ nhớ cache, vì vậy nó hoạt động giống như một giá trị thay đổi theo thời gian. Với điều này, không cần nullkiểm tra như trong trường hợp BehaviorSubjectkhởi tạo với a null. Trong trường hợp này, không có giá trị nào được phát cho người đăng ký cho đến lần xuất bản đầu tiên.

Vì vậy, nó thực sự phụ thuộc vào hành vi bạn đang mong đợi (như hành vi sẽ sử dụng). Hầu hết thời gian bạn có thể sẽ muốn sử dụng BehaviorSubjectvì những gì bạn thực sự muốn đại diện là ngữ nghĩa "giá trị theo thời gian". Nhưng cá nhân tôi không thấy có gì sai với việc thay thế ReplaySubjectkhởi tạo bằng 1.

Những gì bạn muốn tránh là sử dụng vani Subjectkhi những gì bạn thực sự cần là một số hành vi lưu vào bộ nhớ đệm. Lấy ví dụ bạn đang viết một trình bảo vệ định tuyến hoặc một giải pháp. Bạn tìm nạp một số dữ liệu trong bảo vệ đó và đặt nó trong một dịch vụ Subject. Sau đó, trong thành phần được định tuyến, bạn đăng ký chủ thể dịch vụ để cố gắng lấy giá trị đó đã được phát ra trong trình bảo vệ. Giáo sư. Giá trị ở đâu? Nó đã được phát ra rồi, DUH. Sử dụng một chủ đề "bộ nhớ đệm"!

Xem thêm:


1
Đây là sự khác biệt ngắn gọn và dễ hiểu. Khi giá trị thay đổi trong dịch vụ và các thành phần cũng thay đổi mà giá trị đó được hiển thị, thì BehaviourSubjects hoặc Replay Subject là giải pháp.
Saiyaff Farouk

1
Cảm ơn bạn! ReplaySubjectvới kích thước bộ đệm là 1 chính xác là những gì tôi cần. Tôi đã có một bộ phận bảo vệ tuyến đường cần giá trị, nhưng cần phải đợi phát xạ đầu tiên. Vì vậy, một BehaviorSubjectkhông cắt nó, vì tôi không muốn có một giá trị ban đầu ( nullsẽ không làm việc, hoặc bởi vì tôi đã sử dụng nó để biểu thị trạng thái)
menehune23

1
@ menehune23 Tôi cũng cần ReplaySubject cho một resolvelớp bảo vệ Angular . Dịch vụ dữ liệu của tôi có thể là không đồng bộ hoặc đồng bộ (nếu dữ liệu đã được truy xuất). Nếu nó là đồng bộ, thì Subject.next () đang được kích hoạt trước khi resolvehàm trả về và được Angular đăng ký trong nội bộ. BehaviourSubject có thể hoạt động, nhưng tôi sẽ phải gọi một cách rõ ràng complete()và cũng có thể thêm các nullkiểm tra cho giá trị ban đầu. Những gì hoạt động là mới ReplaySubject<DataType>(1)resolveSubject.asObservable().take(1).map(....)
Drenai

1
Tôi đang sử dụng một ReplaySubject với kích thước bộ đệm là 1 nhưng vì một số lý do khi tôi nhận được một Observable với .asObservable()Observable gửi giá trị nulltới người đăng ký trước khi tôi gọi next()trên ReplaySubject của mình. Tôi nghĩ rằng nó không được cho là có giá trị ban đầu không giống như BehaviorSubject?
Kyle V.

2
Tôi nghĩ một ví dụ khá dễ dàng mà bạn có thể đề cập cho chủ đề phát lại sẽ là kịch bản "phòng trò chuyện" hoặc trò chơi vận động hành lang nơi bạn muốn những người mới tham gia xem 10 tin nhắn cuối cùng.
James

14

Một bản tóm tắt tiện dụng về các kiểu quan sát khác nhau, cách đặt tên không trực quan mà tôi biết lol .

  • Subject - Một người đăng ký sẽ chỉ nhận được các giá trị được công bố sau khi đăng ký được thực hiện.
  • BehaviorSubject - Người đăng ký mới nhận được giá trị công bố cuối cùng HOẶC giá trị ban đầu ngay khi đăng ký.
  • ReplaySubject - Người đăng ký mới nhận được tất cả (các) giá trị đã xuất bản trước đó ngay lập tức khi đăng ký

1-n giá trị được công bố? Vì vậy, nếu có 2 giá trị được công bố, một ReplaySubject sẽ tạo ra -1 giá trị được công bố ???
Jason Cheng

@JasonCheng không nó truy xuất tất cả các giá trị đã xuất bản trước đó khi đăng ký, cập nhật câu trả lời :)
Ricky Boyce

11
  1. Chủ đề : Khi đăng ký, nó luôn nhận được dữ liệu được đẩy sau khi đăng ký, tức là các giá trị được đẩy trước đó không được nhận .
const mySubject = new Rx.Subject();

mySubject.next(1);

const subscription1 = mySubject.subscribe(x => {
  console.log('From subscription 1:', x);
});

mySubject.next(2);

const subscription2 = mySubject.subscribe(x => {
  console.log('From subscription 2:', x);
});

mySubject.next(3);

subscription1.unsubscribe();

mySubject.next(4);

Với ví dụ này, đây là kết quả sẽ được in trong bảng điều khiển:

From subscription 1: 2
From subscription 1: 3
From subscription 2: 3
From subscription 2: 4

Lưu ý rằng các đăng ký đến muộn sẽ bỏ sót một số dữ liệu được đưa vào chủ đề như thế nào.

  1. Các chủ đề phát lại : có thể giúp đỡ bằng cách giữ một bộ đệm các giá trị trước đó sẽ được phát cho các đăng ký mới.

Dưới đây là một ví dụ sử dụng cho các chủ đề phát lại trong đó a buffer of 2 previous valuesđược lưu giữ và phát ra trên các đăng ký mới:

const mySubject = new Rx.ReplaySubject(2);

mySubject.next(1);
mySubject.next(2);
mySubject.next(3);
mySubject.next(4);

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});

Đây là những gì mang lại cho chúng ta ở bảng điều khiển:

From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
  1. Chủ thể hành vi : tương tự như chủ thể phát lại, nhưng sẽ chỉ phát lại giá trị được phát cuối cùng hoặc giá trị mặc định nếu không có giá trị nào được phát trước đó:
const mySubject = new Rx.BehaviorSubject('Hey now!');

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});

Và kết quả:

From 1st sub: Hey now!
From 1st sub: 5
From 2nd sub: 5

Tham khảo: https://alligator.io/rxjs/subjects/


4

Từ: Randall Koutnik cuốn sách “Xây dựng các trang web phản ứng với RxJS”. :

Một đề là một đối tượng đó là một turbocharged thể quan sát được. Về cốt lõi, Chủ thể hoạt động giống như một đối tượng có thể quan sát thông thường, nhưng mỗi đăng ký được nối vào cùng một nguồn. Đối tượng cũng là những người quan sát và có các phương pháp tiếp theo, lỗi và thực hiện để gửi dữ liệu đến tất cả các thuê bao cùng một lúc. Bởi vì đối tượng là người quan sát, chúng có thể được chuyển trực tiếp vào cuộc gọi đăng ký và tất cả các sự kiện từ đối tượng có thể quan sát ban đầu sẽ được gửi thông qua đối tượng đến người đăng ký của nó.

Chúng ta có thể sử dụng ReplaySubject để theo dõi lịch sử. Một ReplaySubject ghi lại n sự kiện cuối cùng và chuyển chúng trở lại cho mọi người đăng ký mới. Ví dụ trong ứng dụng trò chuyện. Chúng tôi có thể sử dụng nó để theo dõi bản ghi lịch sử trò chuyện trước đó.

Một BehaviorSubject là một phiên bản đơn giản của ReplaySubject . Các ReplaySubject lưu trữ một số tùy ý các sự kiện, các BehaviorSubject chỉ ghi giá trị của sự kiện mới nhất. Bất cứ khi nào BehaviorSubject ghi lại một đăng ký mới, nó sẽ phát ra giá trị mới nhất cho người đăng ký cũng như bất kỳ giá trị mới nào được chuyển vào. BehaviorSubject hữu ích khi xử lý các đơn vị trạng thái đơn lẻ, chẳng hạn như các tùy chọn cấu hình.


1

Hầu hết câu trả lời được ủng hộ rõ ràng là sai khi tuyên bố rằng:

"Nếu bạn khởi tạo a ReplaySubjectvới kích thước bộ đệm là 1, thì nó thực sự hoạt động giống như BehaviorSubject"


Điều này không hoàn toàn đúng; kiểm tra bài đăng blog tuyệt vời này về sự khác biệt giữa hai điều đó. Ví dụ: nếu bạn đăng ký một hoàn thành BehaviorSubject, bạn sẽ không nhận được giá trị cuối cùng nhưng đối với một, ReplaySubject(1)bạn sẽ nhận được giá trị cuối cùng.

Đây là điểm khác biệt quan trọng không nên bỏ qua:

const behavior = new BehaviorSubject(null);
const replay = new ReplaySubject(1);

behavior.skip(1).subscribe(v => console.log('BehaviorSubject:', v));
replay.subscribe(v => console.log('ReplaySubject:', v));

behavior.next(1);
behavior.next(2);
behavior.complete();
behavior.subscribe(v => console.log('Late B subscriber:', v));

replay.next(1);
replay.next(2);
replay.complete();
replay.subscribe(v => console.log('Late R subscriber:', v));

Kiểm tra ví dụ mã này ở đây đến từ một bài đăng blog tuyệt vời khác về chủ đề này.


0
     // ***********Subject  concept ***********
    let subject = new Subject<string>();


    subject.next("Eureka");
    subject.subscribe((data) => {
      console.log("Subscriber 1 got data >>>>> "+ data);
    });
    subject.subscribe((data) => {
      console.log("Subscriber 2 got data >>>>> "+ data);
    });

       // ********behaviour subject*********
    // Behavior subjects need a first value
let subject1 = new BehaviorSubject<string>("First value");


subject1.asObservable().subscribe((data) => {
  console.log("First subscriber got data behaviour subject>>>>> "+ data);
});
subject1.next("Second value")
  • Chủ đề - Một người đăng ký sẽ chỉ nhận được các giá trị đã xuất bản sau khi đăng ký được thực hiện.
  • BehaviorSubject - Người đăng ký mới nhận được giá trị được xuất bản lần cuối HOẶC giá trị ban đầu ngay khi đăng ký.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.