--- Chỉnh sửa 4 - Tài nguyên bổ sung (2018/09/01)
Trong một tập gần đây của Adventures in Angular Ben Lesh và Ward Bell thảo luận về các vấn đề xung quanh cách thức / thời điểm hủy đăng ký thành phần. Cuộc thảo luận bắt đầu vào khoảng 1:05:30.
Ward đề cập right now there's an awful takeUntil dance that takes a lot of machinery
và Shai Reznik đề cập Angular handles some of the subscriptions like http and routing
.
Đáp lại, Ben đề cập rằng có các cuộc thảo luận ngay bây giờ để cho phép Observables kết nối với các sự kiện vòng đời thành phần Angular và Ward gợi ý một sự kiện quan sát trong vòng đời mà một thành phần có thể đăng ký như một cách để biết khi nào hoàn thành Observables được duy trì như trạng thái bên trong thành phần.
Điều đó nói rằng, chúng ta chủ yếu cần các giải pháp ngay bây giờ vì vậy đây là một số tài nguyên khác.
Một khuyến nghị cho takeUntil()
mẫu từ thành viên nhóm nòng cốt RxJs Nicholas Jamieson và một quy tắc tslint để giúp thực thi nó. https://ncjamieson.com/avoiding-takeuntil-leaks/
Gói npm nhẹ hiển thị toán tử có thể quan sát được, lấy một thể hiện thành phần ( this
) làm tham số và tự động hủy đăng ký trong khi ngOnDestroy
.
https://github.com/NetanelBasal/ngx-take-until-destroy
Một biến thể khác ở trên với công thái học tốt hơn một chút nếu bạn không thực hiện các bản dựng AOT (nhưng tất cả chúng ta nên thực hiện AOT ngay bây giờ).
https://github.com/smnbbrv/ngx-rx-collector
Chỉ thị tùy chỉnh *ngSubscribe
hoạt động như ống async nhưng tạo chế độ xem được nhúng trong mẫu của bạn để bạn có thể tham khảo giá trị 'chưa được bao bọc' trong toàn bộ mẫu của mình.
https://netbasal.com/diy-subcrip-handling-directive-in-angular-c8f6e762697f
Tôi đã đề cập trong một bình luận trên blog của Nicholas rằng việc sử dụng quá mức takeUntil()
có thể là một dấu hiệu cho thấy thành phần của bạn đang cố gắng làm quá nhiều và nên tách các thành phần hiện có của bạn thành các thành phần Tính năng và Trình bày . Sau đó, bạn có thể | async
quan sát từ thành phần Tính năng thành một Input
thành phần Trình bày, có nghĩa là không cần đăng ký ở bất cứ đâu. Tìm hiểu thêm về phương pháp này ở đây
--- Chỉnh sửa 3 - Giải pháp 'Chính thức' (2017/04/09)
Tôi đã nói chuyện với Ward Bell về câu hỏi này tại NGConf (tôi thậm chí đã chỉ cho anh ấy câu trả lời mà anh ấy nói là đúng) nhưng anh ấy nói với tôi rằng nhóm tài liệu cho Angular có một giải pháp cho câu hỏi này chưa được công bố (mặc dù họ đang làm việc để được chấp thuận ). Ông cũng nói với tôi rằng tôi có thể cập nhật câu trả lời SO của mình với khuyến nghị chính thức sắp tới.
Giải pháp tất cả chúng ta nên sử dụng trong tương lai là thêm một private ngUnsubscribe = new Subject();
trường vào tất cả các thành phần có .subscribe()
lệnh gọi đến Observable
s trong mã lớp của chúng.
Chúng tôi sau đó gọi this.ngUnsubscribe.next(); this.ngUnsubscribe.complete();
trong ngOnDestroy()
phương pháp của chúng tôi .
Nước sốt bí mật (như đã được ghi nhận bởi @metamaker ) là gọi takeUntil(this.ngUnsubscribe)
trước mỗi .subscribe()
cuộc gọi của chúng tôi sẽ đảm bảo tất cả các đăng ký sẽ được dọn sạch khi thành phần bị phá hủy.
Thí dụ:
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();
}
}
Lưu ý: Điều quan trọng là thêm takeUntil
toán tử là toán tử cuối cùng để tránh rò rỉ với các vật quan sát trung gian trong chuỗi toán tử.
--- Chỉnh sửa 2 (2016/12/28)
Nguồn 5
Hướng dẫn Angular, chương Routing hiện nêu như sau: "Bộ định tuyến quản lý các thiết bị quan sát mà nó cung cấp và bản địa hóa các đăng ký. Các đăng ký được dọn sạch khi thành phần bị phá hủy, bảo vệ chống rò rỉ bộ nhớ, vì vậy chúng tôi không cần hủy đăng ký các thông số tuyến đường quan sát được. " - Mark Rajcok
Dưới đây là một cuộc thảo luận về các vấn đề Github cho các tài liệu Angular liên quan đến Bộ quan sát Bộ định tuyến trong đó Ward Bell đề cập đến việc làm rõ tất cả những điều này đang được thực hiện.
--- Chỉnh sửa 1
Nguồn 4
Trong video này từ NgEurope Rob Wormald cũng nói rằng bạn không cần hủy đăng ký khỏi Bộ quan sát Bộ định tuyến. Ông cũng đề cập đến http
dịch vụ và ActivatedRoute.params
trong video này từ tháng 11 năm 2016 .
--- Câu trả lời gốc
TLDR:
Đối với câu hỏi này, có (2) loại Observables
- giá trị hữu hạn và giá trị vô hạn .
http
Observables
tạo ra các giá trị hữu hạn (1) và một cái gì đó giống như DOM event listener
Observables
tạo ra các giá trị vô hạn .
Nếu bạn gọi thủ công subscribe
(không sử dụng ống async), thì unsubscribe
từ vô hạn Observables
.
Đừng lo lắng về những cái hữu hạn , RxJs
sẽ chăm sóc chúng.
Nguồn 1
Tôi đã theo dõi câu trả lời từ Rob Wormald trong Angular's Gitter tại đây .
Ông tuyên bố (tôi tổ chức lại cho rõ ràng và nhấn mạnh là của tôi)
nếu đó là một chuỗi giá trị đơn (như yêu cầu http) thì việc dọn dẹp thủ công là không cần thiết (giả sử bạn đăng ký trong bộ điều khiển theo cách thủ công)
tôi nên nói "nếu đó là một chuỗi hoàn thành " (trong đó các chuỗi giá trị đơn, a la http, là một)
nếu đó là một chuỗi vô hạn , bạn nên hủy đăng ký ống async nào cho bạn
Ngoài ra, ông còn đề cập đến video youtube này trên Đài quan sát rằng they clean up after themselves
... trong bối cảnh của Đài quan sát complete
(như Promise, luôn hoàn thành vì chúng luôn tạo ra 1 giá trị và kết thúc - chúng tôi không bao giờ lo lắng về việc hủy đăng ký từ Promise để đảm bảo chúng dọn sạch xhr
sự kiện người nghe, phải không?).
Nguồn 2
Cũng trong hướng dẫn Rangle cho Angular 2, nó đọc
Trong hầu hết các trường hợp, chúng tôi sẽ không cần phải gọi một cách rõ ràng phương thức hủy đăng ký trừ khi chúng tôi muốn hủy sớm hoặc Observable của chúng tôi có tuổi thọ dài hơn đăng ký của chúng tôi. Hành vi mặc định của các nhà khai thác quan sát là loại bỏ đăng ký ngay khi các thông báo .complete () hoặc .error () được xuất bản. Hãy nhớ rằng RxJS được thiết kế để được sử dụng theo kiểu "lửa và quên" hầu hết thời gian.
Khi nào cụm từ our Observable has a longer lifespan than our subscription
áp dụng?
Nó áp dụng khi đăng ký được tạo bên trong một thành phần bị hủy trước đó (hoặc không phải là "lâu" trước khi Observable
hoàn thành.
Tôi đọc điều này có nghĩa là nếu chúng tôi đăng ký một http
yêu cầu hoặc có thể quan sát được phát ra 10 giá trị và thành phần của chúng tôi bị hủy trước khi http
yêu cầu đó trả về hoặc 10 giá trị đã được phát ra, chúng tôi vẫn ổn!
Khi yêu cầu trở lại hoặc giá trị thứ 10 cuối cùng được phát ra, Observable
nó sẽ hoàn thành và tất cả các tài nguyên sẽ được dọn sạch.
Nguồn 3
Nếu chúng ta nhìn vào ví dụ này so với cùng Rangle hướng dẫn chúng ta có thể thấy rằng Subscription
để route.params
không đòi hỏi một unsubscribe()
bởi vì chúng ta không biết khi nào những params
sẽ ngừng thay đổi (phát ra những giá trị mới).
Thành phần này có thể bị phá hủy bằng cách điều hướng đi trong trường hợp thông số tuyến có thể vẫn sẽ thay đổi (chúng có thể thay đổi về mặt kỹ thuật cho đến khi ứng dụng kết thúc) và tài nguyên được phân bổ trong đăng ký vẫn sẽ được phân bổ vì chưa có completion
.
Subscription
shttp-requests
có thể bị bỏ qua, vì họ chỉ gọionNext
một lần và sau đó họ gọionComplete
. CácRouter
thay vì gọionNext
nhiều lần và có thể không bao giờ gọionComplete
(không chắc chắn về điều đó ...). Tương tự vớiObservable
s từEvent
s. Vì vậy, tôi đoán những người nên đượcunsubscribed
.