--- Sunting 4 - Sumber Daya Tambahan (2018/09/01)
Dalam episode baru-baru ini dari Adventures in Angular Ben Lesh dan Ward Bell membahas masalah seputar bagaimana / kapan harus berhenti berlangganan suatu komponen. Diskusi dimulai pada sekitar 1:05:30.
Ward menyebutkan right now there's an awful takeUntil dance that takes a lot of machinery
dan Shai Reznik menyebutkan Angular handles some of the subscriptions like http and routing
.
Sebagai tanggapan, Ben menyebutkan bahwa ada diskusi sekarang untuk memungkinkan Observable untuk terhubung ke peristiwa siklus hidup komponen Angular dan Ward menyarankan Observable peristiwa siklus hidup yang dapat berlangganan sebagai cara untuk mengetahui kapan harus menyelesaikan Observable yang dikelola sebagai keadaan internal komponen.
Yang mengatakan, kita sebagian besar membutuhkan solusi sekarang jadi di sini adalah beberapa sumber
Sebuah rekomendasi untuk takeUntil()
pola dari anggota tim inti RxJs Nicholas Jamieson dan aturan tslint untuk membantu menegakkannya. https://ncjamieson.com/avoiding-takeuntil-leaks/
Paket npm ringan yang mengekspos operator yang dapat diobservasi yang menggunakan instance komponen ( this
) sebagai parameter dan secara otomatis berhenti berlangganan selama ngOnDestroy
.
https://github.com/NetanelBasal/ngx-take-until-destroy
Variasi lain di atas dengan ergonomi yang sedikit lebih baik jika Anda tidak melakukan build AOT (tetapi kita semua harus melakukan AOT sekarang).
https://github.com/smnbbrv/ngx-rx-collector
Arahan khusus *ngSubscribe
yang berfungsi seperti pipa async tetapi membuat tampilan tertanam di templat Anda sehingga Anda dapat merujuk ke nilai 'tidak terbuka' di seluruh templat Anda.
https://netbasal.com/diy-subscription-handling-directive-in-angular-c8f6e762697f
Saya menyebutkan dalam komentar di blog Nicholas bahwa penggunaan berlebihan takeUntil()
bisa menjadi pertanda bahwa komponen Anda mencoba melakukan terlalu banyak dan bahwa memisahkan komponen yang ada menjadi komponen Fitur dan Presentasi harus dipertimbangkan. Anda kemudian dapat | async
diamati dari komponen Fitur ke Input
dalam komponen Presentational, yang berarti tidak ada langganan yang diperlukan di mana pun. Baca lebih lanjut tentang pendekatan ini di sini
--- Sunting 3 - Solusi 'Resmi' (2017/04/09)
Saya berbicara dengan Ward Bell tentang pertanyaan ini di NGConf (Saya bahkan menunjukkan kepadanya jawaban ini yang menurutnya benar) tetapi dia mengatakan kepada saya bahwa tim dokumen untuk Angular memiliki solusi untuk pertanyaan ini yang tidak dipublikasikan (walaupun mereka sedang berusaha untuk mendapatkan persetujuannya) ). Dia juga mengatakan kepada saya bahwa saya dapat memperbarui jawaban SO saya dengan rekomendasi resmi yang akan datang.
Solusi yang kita semua harus gunakan maju adalah menambahkan private ngUnsubscribe = new Subject();
bidang ke semua komponen yang memiliki .subscribe()
panggilan ke Observable
dalam kode kelas mereka.
Kami kemudian memanggil metode this.ngUnsubscribe.next(); this.ngUnsubscribe.complete();
kami ngOnDestroy()
.
Saus rahasia (sebagaimana telah dicatat oleh @metamaker ) adalah untuk menelepon takeUntil(this.ngUnsubscribe)
sebelum masing-masing .subscribe()
panggilan kami yang akan menjamin semua langganan akan dibersihkan ketika komponen dihancurkan.
Contoh:
import { Component, OnDestroy, OnInit } from '@angular/core';
// RxJs 6.x+ import paths
import { filter, startWith, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { BookService } from '../books.service';
@Component({
selector: 'app-books',
templateUrl: './books.component.html'
})
export class BooksComponent implements OnDestroy, OnInit {
private ngUnsubscribe = new Subject();
constructor(private booksService: BookService) { }
ngOnInit() {
this.booksService.getBooks()
.pipe(
startWith([]),
filter(books => books.length > 0),
takeUntil(this.ngUnsubscribe)
)
.subscribe(books => console.log(books));
this.booksService.getArchivedBooks()
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(archivedBooks => console.log(archivedBooks));
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
Catatan: Penting untuk menambahkan takeUntil
operator sebagai yang terakhir untuk mencegah kebocoran dengan yang dapat diamati antara dalam rantai operator.
--- Edit 2 (2016/12/28)
Sumber 5
Tutorial Angular, bab Routing sekarang menyatakan sebagai berikut: "Router mengelola observable yang disediakan dan melokalisasi langganan. Langganan dibersihkan ketika komponen dihancurkan, melindungi terhadap kebocoran memori, jadi kita tidak perlu berhenti berlangganan dari rute params Teramati. " - Mark Rajcok
Berikut ini adalah diskusi tentang masalah Github untuk dokumen Angular mengenai Router Observables di mana Ward Bell menyebutkan bahwa klarifikasi untuk semua ini sedang dikerjakan.
--- Edit 1
Sumber 4
Dalam video ini dari NgEurope Rob Wormald juga mengatakan Anda tidak perlu berhenti berlangganan dari Router Observables. Dia juga menyebutkan http
layanan dan ActivatedRoute.params
dalam video ini dari November 2016 .
--- Jawaban Asli
TLDR:
Untuk pertanyaan ini ada (2) jenis Observables
- nilai terbatas dan nilai tak terbatas .
http
Observables
menghasilkan nilai hingga (1) dan sesuatu seperti DOM event listener
Observables
menghasilkan nilai tak hingga .
Jika Anda memanggil secara manual subscribe
(tidak menggunakan pipa async), maka unsubscribe
dari infinite Observables
.
Jangan khawatir tentang yang terbatas , RxJs
akan mengurusnya.
Sumber 1
Saya melacak jawaban dari Rob Wormald di Angular's Gitter di sini .
Dia menyatakan (saya mengatur ulang untuk kejelasan dan penekanan adalah milikku)
jika ini adalah single-value-sequence (seperti permintaan http) pembersihan manual tidak diperlukan (dengan asumsi Anda berlangganan controller secara manual)
saya harus mengatakan "jika itu urutan yang melengkapi " (yang urutan nilai tunggal, ala http, adalah satu)
jika urutannya tidak terbatas , Anda harus berhenti berlangganan yang mana dilakukan oleh pipa async untuk Anda
Dia juga menyebutkan dalam video youtube ini di Observables that they clean up after themselves
... dalam konteks Observables yang complete
(seperti Janji, yang selalu lengkap karena mereka selalu menghasilkan 1 nilai dan berakhir - kami tidak pernah khawatir tentang berhenti berlangganan dari Janji untuk memastikan mereka membersihkan xhr
acara pendengar, kan?).
Sumber 2
Juga di panduan Rangle ke Angular 2 berbunyi
Dalam kebanyakan kasus, kita tidak perlu secara eksplisit memanggil metode berhenti berlangganan kecuali jika kita ingin membatalkan lebih awal atau Observable kita memiliki umur yang lebih panjang daripada berlangganan kita. Perilaku default dari operator yang dapat diobservasi adalah membuang langganan begitu pesan .complete () atau .error () dipublikasikan. Perlu diingat bahwa RxJS dirancang untuk digunakan dalam mode "api dan lupakan" sebagian besar waktu.
Kapan frasa ini our Observable has a longer lifespan than our subscription
berlaku?
Ini berlaku ketika langganan dibuat di dalam komponen yang dihancurkan sebelum (atau tidak 'lama' sebelum) Observable
selesai.
Saya membaca ini sebagai makna jika kita berlangganan http
permintaan atau yang dapat diamati yang memancarkan 10 nilai dan komponen kita dihancurkan sebelum http
permintaan itu kembali atau 10 nilai telah dipancarkan, kita masih ok!
Ketika permintaan kembali atau nilai ke-10 akhirnya dikeluarkan Observable
akan menyelesaikan dan semua sumber daya akan dibersihkan.
Sumber 3
Jika kita melihat contoh ini dari panduan Rangle yang sama, kita dapat melihat bahwa Subscription
to route.params
tidak memerlukan unsubscribe()
karena kita tidak tahu kapan mereka params
akan berhenti berubah (mengeluarkan nilai baru).
Komponen dapat dihancurkan dengan menavigasi pergi dalam hal ini params rute kemungkinan masih akan berubah (mereka secara teknis bisa berubah sampai aplikasi berakhir) dan sumber daya yang dialokasikan dalam berlangganan masih akan dialokasikan karena belum ada completion
.
Subscription
shttp-requests
dapat diabaikan, karena mereka hanya memanggilonNext
sekali dan kemudian mereka memanggilonComplete
. TheRouter
bukan panggilanonNext
berulang-ulang dan mungkin tidak pernah memanggilonComplete
(tidak yakin tentang itu ...). Sama berlaku untukObservable
s dariEvent
s. Jadi saya kira itu seharusnyaunsubscribed
.