2017-02-27 17 views
9

tl; डॉ: असल में मैं एंगुलर के ngOnDestroy से Rxjs takeUntil() ऑपरेटर के साथ शादी करना चाहता हूं। -- क्या यह संभव है?आरएक्सजेएस: टेकयूनीट() कोणीय घटक का ngOnDestroy()

मेरे पास एक कोणीय घटक है जो कई Rxjs सदस्यता खोलता है। घटक नष्ट होने पर इन्हें बंद करने की आवश्यकता है।

इस के लिए एक सरल समाधान होगा:

class myComponent { 

    private subscriptionA; 
    private subscriptionB; 
    private subscriptionC; 

    constructor(
    private serviceA: ServiceA, 
    private serviceB: ServiceB, 
    private serviceC: ServiceC) {} 

    ngOnInit() { 
    this.subscriptionA = this.serviceA.subscribe(...); 
    this.subscriptionB = this.serviceB.subscribe(...); 
    this.subscriptionC = this.serviceC.subscribe(...); 
    } 

    ngOnDestroy() { 
    this.subscriptionA.unsubscribe(); 
    this.subscriptionB.unsubscribe(); 
    this.subscriptionC.unsubscribe(); 
    } 

} 

यह काम करता है, लेकिन यह थोड़ा निरर्थक है। मुझे विशेष रूप से यह पसंद नहीं है कि - unsubscribe() कहीं और है, इसलिए आपको याद रखना होगा कि ये जुड़े हुए हैं। - घटक राज्य सदस्यता के साथ प्रदूषित है।

मैं बहुत takeUntil() ऑपरेटर या कुछ इसी तरह का उपयोग कर पसंद करते हैं, यह इस तरह दिखेगा बनाने के लिए होगा:

class myComponent { 

    constructor(
    private serviceA: ServiceA, 
    private serviceB: ServiceB, 
    private serviceC: ServiceC) {} 

    ngOnInit() { 
    const destroy = Observable.fromEvent(???).first(); 
    this.subscriptionA = this.serviceA.subscribe(...).takeUntil(destroy); 
    this.subscriptionB = this.serviceB.subscribe(...).takeUntil(destroy); 
    this.subscriptionC = this.serviceC.subscribe(...).takeUntil(destroy); 
    } 

} 

वहाँ है एक को नष्ट घटना या कुछ इसी तरह है कि मुझे takeUntil() का उपयोग करते हैं या किसी अन्य तरीके से सरल करने के लिए उस तरह के घटक वास्तुकला? मुझे एहसास है कि मैं खुद को कन्स्ट्रक्टर या कुछ ऐसा कर सकता हूं जो ngOnDestroy() के भीतर ट्रिगर हो जाता है लेकिन अंत में चीजों को पढ़ने के लिए इतना आसान नहीं होगा।

उत्तर

18

आपको लगता है कि के लिए एक ReplaySubject का लाभ उठाने कर सकते हैं:

class myComponent { 
    private destroyed$: ReplaySubject<boolean> = new ReplaySubject(1); 

    constructor(
    private serviceA: ServiceA, 
    private serviceB: ServiceB, 
    private serviceC: ServiceC) {} 

    ngOnInit() { 
    this.serviceA 
     .takeUntil(this.destroyed$) 
     .subscribe(...); 
    this.serviceB 
     .takeUntil(this.destroyed$) 
     .subscribe(...); 
    this.serviceC 
     .takeUntil(this.destroyed$) 
     .subscribe(...); 
    } 

    ngOnDestroy() { 
    this.destroyed$.next(true); 
    this.destroyed$.complete(); 
    } 
} 
+0

एक तरह से यह वही नहीं था जो मैं चाहता था - मैं घटक में एक अतिरिक्त राज्य आर्टिफैक्ट बनाने से बचाना चाहता था ('$ नष्ट ') और इसे' ngOnDestroy' से ट्रिगर करना। लेकिन मुझे यह देखने के बाद पता चला है कि इस के आसपास जाने के लिए कोई वाक्य रचनात्मक चीनी नहीं है। सभी सदस्यता को संग्रहीत करने के बावजूद यह निश्चित रूप से पहले से ही एक अच्छा समाधान है। धन्यवाद! – JeffreyHammansson

+1

कोणीय टीम में चर्चा हुई है कि एक घटक में आरएक्सजे के लिए आसानी से सुलभ घटना को कैसे पहुंचाया जा सकता है, लेकिन जहां तक ​​मैं kmow कुछ भी लागू नहीं किया गया है। – olsn

+2

मैं यहां 'नया रीप्लेसब्जेक्ट (1)' पर विचार करूंगा। इस तरह आपका घटक नष्ट राज्य में रहेगा और आप सुनिश्चित हैं कि सबकुछ पूरा हो गया है। इसके अलावा, अच्छा जवाब :) – Dorus

8

खैर, यह आप एक सदस्यता बंद करके क्या मतलब करने के लिए नीचे आता है। ऐसा करने के मूल रूप से दो तरीके हैं:

  1. श्रृंखला को पूरा करने वाले ऑपरेटर का उपयोग करना (जैसे takeWhile())।
  2. स्रोत पर्यवेक्षक से सदस्यता छोड़ें।

यह जानना अच्छा है कि ये दोनों समान नहीं हैं।

उदाहरण के लिए takeWhile() का उपयोग करते समय आप ऑपरेटर को complete अधिसूचना भेजते हैं जो आपके पर्यवेक्षकों के लिए प्रचारित होता है। तो यदि आप परिभाषित करते हैं:

... 
.subscribe(..., ...,() => doWhatever()); 

फिर जब आप श्रृंखला के साथ श्रृंखला को पूरा करते हैं। takeWhile()doWhatever() फ़ंक्शन को कॉल किया जाएगा।

उदाहरण के लिए यह ऐसा दिखाई दे सकता:

const Observable = Rx.Observable; 
const Subject = Rx.Subject; 

let source = Observable.timer(0, 1000); 
let subject = new Subject(); 

source.takeUntil(subject).subscribe(null, null,() => console.log('complete 1')); 
source.takeUntil(subject).subscribe(null, null,() => console.log('complete 2')); 
source.takeUntil(subject).subscribe(null, null,() => console.log('complete 3')); 

setTimeout(() => { 
    subject.next(); 
}, 3000); 

3s आखिर पूरा कॉलबैक बुलाया जाएगा।

दूसरी ओर जब आप सदस्यता छोड़ते हैं तो आप कह रहे हैं कि अब आप स्रोत पर्यवेक्षक द्वारा उत्पादित वस्तुओं में रुचि नहीं रखते हैं। हालांकि इसका मतलब यह नहीं है कि स्रोत को पूरा करना है। आप अभी और परवाह नहीं करते हैं।

इसका मतलब यह है कि आप .subscribe(...) कॉल से सभी Subscription रों इकट्ठा करने और उन सभी को एक ही बार में छोड़ सकते हैं:

let subscriptions = new Rx.Subscription(); 
let source = Observable.timer(0, 1000); 

subscriptions.add(source.subscribe(null, null,() => console.log('complete 1'))); 
subscriptions.add(source.subscribe(null, null,() => console.log('complete 2'))); 
subscriptions.add(source.subscribe(null, null,() => console.log('complete 3'))); 

setTimeout(() => { 
    subscriptions.unsubscribe(); 
}, 3000); 

अब के बाद 3s देरी कुछ भी नहीं सांत्वना देने मुद्रित किया जाएगा क्योंकि हम से समाप्त कर दी है और कोई पूरा कॉलबैक लागू किया गया था ।

तो आप जो भी उपयोग करना चाहते हैं वह आपके और आपके उपयोग-मामले पर निर्भर है। बस जागरूक रहें कि सदस्यता रद्द करने के समान ही नहीं है, भले ही मैं आपकी स्थिति में अनुमान लगाता हूं, इससे कोई फर्क नहीं पड़ता।

+0

शायद ध्यान देने योग्य है कि किसी को स्ट्रीम शुरू नहीं करना चाहिए, जो किसी घटक के भीतर से सीधे पूरा होना चाहिए - किसी भी महत्वपूर्ण ऑपरेशन को सेवा के माध्यम से किया जाना चाहिए, जो रूट-चेंज के माध्यम से नष्ट होने के खतरे में नहीं है। – olsn

+0

मुझे वास्तव में उस संदर्भ में कई पूर्ण स्ट्रीमों का सामना नहीं हुआ है, क्योंकि अधिकांश खुले अंत में हैं और घटक कुछ बिंदु पर सुनना बंद कर देते हैं। लेकिन मुझे निश्चित रूप से लगता है कि सदस्यता रद्द करने से दीर्घकालिक हो सकता है, यहां सिद्धांत से बाहर आवेदन करने के लिए बेहतर पैटर्न हो सकता है, क्योंकि यह तर्कसंगत रूप से होने वाला है। मैं इसके बारे में सोचूंगा। धन्यवाद! – JeffreyHammansson

+0

स्ट्रीम पर 'takeUntil (Rx.Observable.timer (3000)) 'पर विचार करें। दरअसल, 'ले लें' के साथ आप 'पूरा' करेंगे, जबकि 'सदस्यता समाप्त करें' के साथ * रद्द करें *। – Dorus

3

NPM पैकेज ng2-rx-componentdestroyed से componentDestroyed() समारोह का उपयोग करना takeUntil दूर सबसे आसान तरीका कर रहा है उपयोग करने के लिए:

@Component({ 
    selector: 'foo', 
    templateUrl: './foo.component.html' 
}) 
export class FooComponent implements OnInit, OnDestroy { 
    ngOnInit() { 
    Observable.interval(1000) 
     .takeUntil(componentDestroyed(this)) // <--- magic is here! 
     .subscribe(console.log); 
    } 

    ngOnDestroy() {} 
} 

यहाँ componentDestroyed() का एक संस्करण है अपने कोड में सीधे शामिल करने के लिए:

// Based on https://www.npmjs.com/package/ng2-rx-componentdestroyed 
import { OnDestroy } from '@angular/core'; 
import { ReplaySubject } from 'rxjs/ReplaySubject'; 

export function componentDestroyed(component: OnDestroy) { 
    const oldNgOnDestroy = component.ngOnDestroy; 
    const destroyed$ = new ReplaySubject<void>(1); 
    component.ngOnDestroy =() => { 
    oldNgOnDestroy.apply(component); 
    destroyed$.next(undefined); 
    destroyed$.complete(); 
    }; 
    return destroyed$; 
} 
संबंधित मुद्दे