javascript - Subject vs BehaviorSubject vs ReplaySubject i Angular
Jag har försökt att förstå de där 3:
- Ämne
- BehaviorSubject
- ReplaySubject
Jag skulle vilja använda dem och veta när och varför, vilka fördelar det finns med att använda dem och även om jag har läst dokumentationen, tittat på handledningar och sökt på Google har jag inte lyckats förstå något av detta.
Så vad är deras syfte? Ett verkligt fall skulle uppskattas mest, det behöver inte ens vara kod.
Jag skulle föredra en tydlig förklaring, inte bara "a+b => c du är prenumererad på ..."
Tack
Svar #1
Det handlar verkligen om beteende och semantik. Med en
Subject- en prenumerant kommer endast att få publicerade värden som emitterades efter prenumerationen. Fråga dig själv, är det vad du vill? Behöver prenumeranten veta något om tidigare värden? Om inte, då kan du använda detta, annars välj en av de andra. Till exempel, vid kommunikation mellan komponenter. Säg att du har en komponent som publicerar händelser för andra komponenter vid ett knapptryck. Du kan använda en tjänst med ett subject för att kommunicera.BehaviorSubject- det senaste värdet cachas. En prenumerant kommer att få det senaste värdet vid första prenumerationen. Semantiken för detta ämne är att representera ett värde som ändras över tid. Till exempel en inloggad användare. Den initiala användaren kan vara en anonym användare. Men när en användare loggar in blir det nya värdet det autentiserade användartillståndet.BehaviorSubjectinitieras med ett initialt värde. Detta är ibland viktigt beroende på kodningspreferens. Säg till exempel att du initierar det mednull. Då behöver du göra en null-kontroll i din prenumeration. Kanske okej, eller kanske irriterande.ReplaySubject- det kan cacha upp till ett angivet antal emissioner. Alla prenumeranter kommer att få alla cachade värden vid prenumeration. När skulle man behöva detta beteende? Ärligt talat har jag inte haft något behov av ett sådant beteende, förutom i följande fall:Om du initialiserar ett
ReplaySubjectmed en buffertstorlek på1, så beter det sig faktiskt precis som ettBehaviorSubject. Det senaste värdet cachas alltid, så det fungerar som ett värde som förändras över tid. Med detta finns det inget behov av ennull-kontroll som i fallet med ettBehaviorSubjectsom initialiserats mednull. I detta fall skickas inget värde till prenumeranten förrän det första publicerandet.
Så det handlar egentligen om det beteende du förväntar dig (när det gäller vilken du ska använda). Oftast kommer du förmodligen vilja använda en BehaviorSubject eftersom det du verkligen vill representera är semantiken "värde över tid". Men personligen ser jag inget fel med att byta ut mot en ReplaySubject initierad med 1.
Det du vill undvika är att använda den vanliga Subject när det du verkligen behöver är någon caching-beteende. Ta till exempel att du skriver en routing-vakt eller en resolve. Du hämtar viss data i den vakten och sätter den i en service Subject. Sedan i den routade komponenten prenumererar du på service-subjektet för att försöka få det värde som emitterades i vakten. Oops. Var är värdet? Det emitterades redan, DUH. Använd ett "caching"-subjekt!
Se även:
- Vad är RxJS Subject och fördelarna med att använda dem?
Svar #2
- Ämne: Vid prenumeration får man alltid de data som pushas efter dess prenumeration, dvs tidigare pushade värden tas inte emot.
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);<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.12/Rx.min.js"></script>Med detta exempel är här resultatet som kommer att skrivas ut i konsolen:
From subscription 1: 2
From subscription 1: 3
From subscription 2: 3
From subscription 2: 4
Notera hur prenumerationer som kommer sent går miste om en del av de data som har skickats in i ämnet.
- Replay-ämnen: kan hjälpa genom att behålla en buffert av tidigare värden som kommer att sändas till nya prenumerationer.
Här är ett användningsexempel för replay-ämnen där en buffert med 2 tidigare värden behålls och skickas vid nya prenumerationer:
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);
});<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.12/Rx.min.js"></script>Här är vad det ger oss på konsolen:
From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
- Behavior-ämnen: är liknande replay-ämnen, men kommer endast att återutsända det senaste utsända värdet, eller ett standardvärde om inget värde tidigare har utsänds:
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);
});<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.12/Rx.min.js"></script>Och resultatet:
From 1st sub: Hey now!
From 1st sub: 5
From 2nd sub: 5
Referens: https://alligator.io/rxjs/subjects/
Svar #3
En praktisk sammanfattning av de olika observerbara typerna, ointuitiva namn vet jag lol.
Subject- En prenumerant kommer bara att få publicerade värden därefter när prenumerationen har gjorts.BehaviorSubject- Nya prenumeranter får det senaste publicerade värdet ELLER startvärdet omedelbart vid prenumeration.ReplaySubject- Nya prenumeranter får alla tidigare publicerade värden direkt vid prenumeration
Svar #4
Den mest uppröstade svaret är helt felaktigt och påstår att:
"Om du initierar ett ReplaySubject med en buffertstorlek på 1, så beter det sig faktiskt precis som ett BehaviorSubject"
Detta är inte helt sant; kolla detta fantastiska blogginlägg om skillnaderna mellan dessa två. Till exempel, om du prenumererar på ett avslutat BehaviorSubject, kommer du inte att få det sista värdet, men för ett ReplaySubject(1) kommer du att få det sista värdet.
Detta är en viktig skillnad som inte bör förbises:
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));
Kolla på detta kodexempel här som kommer från ett annat bra blogginlägg om ämnet.
Svar #5
Från: Randall Koutniks bok "Bygg reaktiva webbplatser med RxJS." :
En Subject är ett objekt som är ett turboladdat observerbart. I grunden fungerar en Subject mycket som ett vanligt observerbart, men varje prenumeration är kopplad till samma källa. Subjects är också observatörer och har next-, error- och done-metoder för att skicka data till alla prenumeranter samtidigt. Eftersom subjects är observatörer, kan de passas direkt till ett subscribe-anrop, och alla händelser från det ursprungliga observerbara objektet kommer att skickas genom subject till dess prenumeranter.
Vi kan använda ReplaySubject för att spåra historik. En ReplaySubject registrerar de senaste n händelserna och spelar upp dem för varje ny prenumerant. Till exempel i en chattapplikation. Vi kan använda den för att spåra tidigare chatt-historik.
En BehaviorSubject är en förenklad version av ReplaySubject. ReplaySubject sparade ett godtyckligt antal händelser, BehaviorSubject registrerar endast värdet av den senaste händelsen. När en BehaviorSubject registrerar en ny prenumeration, skickar den ut det senaste värdet till prenumeranten samt alla nya värden som tillkommer. BehaviorSubject är användbar när man hanterar enskilda tillståndsenheter, såsom konfigurationsalternativ.
