Angular / RxJs Khi nào tôi nên hủy đăng ký `` Đăng ký ''

770
Sergey Tihon 2016-06-24 21:52.

Khi nào tôi nên lưu trữ các Subscriptionphiên bản và gọi unsubscribe()trong vòng đời NgOnDestroy và khi nào tôi có thể bỏ qua chúng?

Lưu tất cả các đăng ký dẫn đến rất nhiều lộn xộn vào mã thành phần.

Hướng dẫn ứng dụng HTTP bỏ qua các đăng ký như thế này:

getHeroes() {
  this.heroService.getHeroes()
                  .subscribe(
                     heroes => this.heroes = heroes,
                     error =>  this.errorMessage = <any>error);
}

Đồng thời, Hướng dẫn Định hướng & Tuyến đường nói rằng:

Cuối cùng, chúng tôi sẽ điều hướng đến một nơi khác. Bộ định tuyến sẽ loại bỏ thành phần này khỏi DOM và phá hủy nó. Chúng ta cần phải tự dọn dẹp trước khi điều đó xảy ra. Cụ thể, chúng ta phải hủy đăng ký trước khi Angular phá hủy thành phần. Không làm như vậy có thể tạo ra rò rỉ bộ nhớ.

Chúng tôi hủy đăng ký Observabletrong ngOnDestroyphương pháp của chúng tôi .

private sub: any;

ngOnInit() {
  this.sub = this.route.params.subscribe(params => {
     let id = +params['id']; // (+) converts string 'id' to a number
     this.service.getHero(id).then(hero => this.hero = hero);
   });
}

ngOnDestroy() {
  this.sub.unsubscribe();
}

21 answers

1026
seangwright 2016-12-16 18:11.

--- Chỉnh sửa 4 - Tài nguyên bổ sung (2018/09/01)

Trong một tập gần đây của Cuộc phiêu lưu ở Angular, Ben Lesh và Ward Bell thảo luận về các vấn đề xung quanh cách / thời điểm hủy đăng ký trong một 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 machineryvà Shai Reznik đề cập Angular handles some of the subscriptions like http and routing.

Trong câu trả lời, Ben đề cập rằng có các cuộc thảo luận ngay bây giờ để cho phép các Observables kết nối vào các sự kiện vòng đời của thành phần Angular và Ward đề xuất một sự kiện vòng đời có thể quan sát được 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 các Observables được duy trì như trạng thái bên trong của thành phần.

Điều đó nói rằng, chúng tôi chủ yếu cần các giải pháp bây giờ vì vậy đây là một số nguồn lực khác.

  1. Đề xuất cho takeUntil()mô hình từ Nicholas Jamieson, thành viên cốt lõi của nhóm RxJs và một quy tắc tslint để giúp thực thi nó. https://ncjamieson.com/avoiding-takeuntil-leaks/

  2. Gói npm nhẹ hiển thị một toán tử có thể quan sát lấy một cá thể thành phần ( this) làm tham số và tự động hủy đăng ký trong ngOnDestroy. https://github.com/NetanelBasal/ngx-take-until-destroy

  3. 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 làm AOT ngay bây giờ). https://github.com/smnbbrv/ngx-rx-collector

  4. Lệnh tùy chỉnh *ngSubscribehoạt động giống như đường ống không đồng bộ 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 gói' trong suốt mẫu của mình. https://netbasal.com/diy-subscription-handling-directive-in-angular-c8f6e762697f

Tôi đề cập trong một nhận xét cho 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à việc 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ăngTrình bày cần được xem xét. Sau đó, bạn có thể | asyncObservable từ thành phần Feature thành một thành phần Inputcủa Presentational, có nghĩa là không cần đăng ký ở bất kỳ đâu. Đọc thêm về cách tiếp cận này tại đâ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í còn cho anh ấy xem câu trả lời này 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 chưa được xuất bản này (mặc dù họ đang làm việc để nó được chấp thuận ). Anh ấy 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 mà 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 Observabletrong mã lớp của chúng.

Sau đó chúng tôi gọi this.ngUnsubscribe.next(); this.ngUnsubscribe.complete();các ngOnDestroy()phương thức của mình.

Nước sốt bí mật (như đã được lưu ý bởi @metamaker ) là gọi takeUntil(this.ngUnsubscribe)trước mỗi .subscribe()cuộc gọi của chúng tôi , điều này 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à phải thêm takeUntiltoán tử làm người cuối cùng để ngăn chặn rò rỉ với các đối tượng 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 Định tuyến hiện nói như sau: "Bộ định tuyến quản lý các vật có thể quan sát được mà nó cung cấp và bản địa hóa các đăng ký. Các đăng ký sẽ được dọn dẹp 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 phải hủy đăng ký the route params Observable. " - Angular / RxJs Khi nào tôi nên hủy đăng ký `` Đăng ký ''

Đâ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 Router Observables, trong đó Ward Bell đề cập rằng 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 phải hủy đăng ký khỏi Router Observables. Anh ấy cũng đề cập đến httpdịch vụ và ActivatedRoute.paramstrong 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 Observablestạo ra giá trị (1) hữu hạn và thứ gì đó giống như DOM event listener Observablestạo ra giá trị vô hạn .

Nếu bạn gọi thủ công subscribe(không sử dụng ống không đồng bộ), thì unsubscribetừ vô hạn Observables .

Đừng lo lắng về những cái hữu hạn , RxJssẽ 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 .

Anh ấy nói (tôi đã sắp xếp lại để rõ ràng và nhấn mạnh là của tôi)

nếu nó 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 một chuỗi của nó hoàn thành " (trong đó các chuỗi giá trị đơn lẻ, a la http, là một)

nếu nó là một chuỗi vô hạn , bạn nên hủy đăng ký mà đường ống không đồng bộ làm cho bạn

Ngoài ra, anh ấy cũng đề cập trong video youtube này trên Observables rằng they clean up after themselves... trong ngữ cảnh của Observables complete(như Promises, 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ý Promises để đảm bảo rằng chúng dọn dẹp xhrsự kiện người nghe, phải không?).

Nguồn 2

Cũng trong hướng dẫn Rangle về Angular 2, nó đọc

Trong hầu hết các trường hợp, chúng tôi sẽ không cần gọi phương thức hủy đăng ký một cách rõ ràng 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 có thể 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ế để sử dụng theo kiểu "lửa và quên" hầu hết thời gian.

Khi nào our Observable has a longer lifespan than our subscriptionáp dụng cụm từ ?

Nó áp dụng khi đăng ký được tạo bên trong một thành phần bị phá hủy trước (hoặc 'không lâu' trước khi) Observablehoàn thành.

Tôi đọc điều này có nghĩa là nếu chúng tôi đăng ký một httpyêu cầu hoặc một thiết bị có thể quan sát phát ra 10 giá trị và thành phần của chúng tôi bị phá hủy trước khi httpyê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ả về hoặc giá trị thứ 10 cuối cùng được phát ra thì Observablesẽ hoàn thành và tất 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 từ cùng một hướng dẫn Rangle, chúng ta có thể thấy rằng việc Subscriptioncần route.paramslàm yêu cầu phải có unsubscribe()bởi vì chúng ta không biết khi nào chúng paramssẽ ngừng thay đổi (tạo ra các giá trị mới).

Thành phần có thể bị phá hủy bằng cách điều hướng đi trong trường hợp đó các thông số tuyến đường có thể vẫn thay đổi (về mặt kỹ thuật chúng có thể thay đổi cho đến khi ứng dụng kết thúc) và tài nguyên được phân bổ trong đăng ký sẽ vẫn được phân bổ vì chưa có completion.

102
metamaker 2017-03-10 02:35.

Bạn không cần phải có nhiều đăng ký và hủy đăng ký theo cách thủ công. Sử dụng Đối tượngtakeUntil combo để xử lý đăng ký như một ông chủ:

import { Subject } from "rxjs"
import { takeUntil } from "rxjs/operators"

@Component({
  moduleId: __moduleName,
  selector: "my-view",
  templateUrl: "../views/view-route.view.html"
})
export class ViewRouteComponent implements OnInit, OnDestroy {
  componentDestroyed$: Subject<boolean> = new Subject()

  constructor(private titleService: TitleService) {}

  ngOnInit() {
    this.titleService.emitter1$
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe((data: any) => { /* ... do something 1 */ })

    this.titleService.emitter2$
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe((data: any) => { /* ... do something 2 */ })

    //...

    this.titleService.emitterN$
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe((data: any) => { /* ... do something N */ })
  }

  ngOnDestroy() {
    this.componentDestroyed$.next(true)
    this.componentDestroyed$.complete()
  }
}

Cách tiếp cận thay thế , được đề xuất Angular / RxJs Khi nào tôi nên hủy đăng ký `` Đăng ký '' , sử dụng takeWhile thay vì takeUntil . Bạn có thể thích nó, nhưng hãy nhớ rằng bằng cách này, việc thực thi Observable của bạn sẽ không bị hủy trên ngDestroy của thành phần của bạn (ví dụ: khi bạn thực hiện các phép tính tốn thời gian hoặc chờ dữ liệu từ máy chủ). Phương thức dựa trên takeUntil , không có nhược điểm này và dẫn đến việc hủy yêu cầu ngay lập tức. Angular / RxJs Khi nào tôi nên hủy đăng ký `` Đăng ký '' .

Vì vậy, đây là mã:

@Component({
  moduleId: __moduleName,
  selector: "my-view",
  templateUrl: "../views/view-route.view.html"
})
export class ViewRouteComponent implements OnInit, OnDestroy {
  alive: boolean = true

  constructor(private titleService: TitleService) {}

  ngOnInit() {
    this.titleService.emitter1$
      .pipe(takeWhile(() => this.alive))
      .subscribe((data: any) => { /* ... do something 1 */ })

    this.titleService.emitter2$
      .pipe(takeWhile(() => this.alive))
      .subscribe((data: any) => { /* ... do something 2 */ })

    // ...

    this.titleService.emitterN$
      .pipe(takeWhile(() => this.alive))
      .subscribe((data: any) => { /* ... do something N */ })
  }

  ngOnDestroy() {
    this.alive = false
  }
}
82
Steven Liekens 2017-05-04 02:00.

Lớp Đăng ký có một tính năng thú vị:

Đại diện cho một tài nguyên dùng một lần, chẳng hạn như việc thực thi một Observable. Đăng ký có một phương pháp quan trọng, hủy đăng ký, không cần tranh cãi và chỉ hủy tài nguyên do đăng ký nắm giữ.
Ngoài ra, các đăng ký có thể được nhóm lại với nhau thông qua phương thức add (), phương thức này sẽ đính kèm một Đăng ký con vào Đăng ký hiện tại. Khi một Đăng ký bị hủy đăng ký, tất cả các con (và cháu của nó) cũng sẽ bị hủy đăng ký.

Bạn có thể tạo một đối tượng Đăng ký tổng hợp để nhóm tất cả các đăng ký của bạn. Bạn thực hiện việc này bằng cách tạo Đăng ký trống và thêm đăng ký vào đó bằng add()phương pháp của nó . Khi thành phần của bạn bị phá hủy, bạn chỉ cần hủy đăng ký gói đăng ký tổng hợp.

@Component({ ... })
export class SmartComponent implements OnInit, OnDestroy {
  private subscriptions = new Subscription();

  constructor(private heroService: HeroService) {
  }

  ngOnInit() {
    this.subscriptions.add(this.heroService.getHeroes().subscribe(heroes => this.heroes = heroes));
    this.subscriptions.add(/* another subscription */);
    this.subscriptions.add(/* and another subscription */);
    this.subscriptions.add(/* and so on */);
  }

  ngOnDestroy() {
    this.subscriptions.unsubscribe();
  }
}
35
Mouneer 2018-08-08 08:03.

Một số phương pháp hay nhất liên quan đến việc hủy đăng ký có thể quan sát bên trong các thành phần Angular:

Trích dẫn từ Routing & Navigation

Khi đăng ký một thành phần có thể quan sát được, bạn hầu như luôn sắp xếp để hủy đăng ký khi thành phần bị hủy.

Có một số quan sát đặc biệt không cần thiết. Các khả năng quan sát ActivateRoute nằm trong số các trường hợp ngoại lệ.

ActivateRoute và các thiết bị quan sát của nó được cách ly với chính Router. Bộ định tuyến sẽ phá hủy một thành phần được định tuyến khi nó không còn cần thiết nữa và ActivateRoute được đưa vào sẽ chết cùng với nó.

Hãy hủy đăng ký bằng mọi cách. Nó là vô hại và không bao giờ là một thực hành xấu.

Và để trả lời các liên kết sau:

Tôi đã thu thập một số phương pháp hay nhất về việc hủy đăng ký có thể quan sát được bên trong các thành phần Angular để chia sẻ với bạn:

  • httpViệc hủy đăng ký có thể quan sát được là có điều kiện và chúng ta nên xem xét các tác động của 'lệnh gọi lại đăng ký' đang được chạy sau khi thành phần bị hủy theo từng trường hợp. Chúng ta biết rằng góc cạnh hủy đăng ký và làm sạch httpchính bản thân có thể quan sát được (1) , Có cần thiết phải hủy đăng ký khỏi các đối tượng quan sát được tạo bởi các phương thức Http không? . Trong khi điều này đúng từ quan điểm của các nguồn lực, nó chỉ kể một nửa câu chuyện. Giả sử chúng ta đang nói về việc gọi trực tiếp httptừ bên trong một thành phần và httpphản hồi mất nhiều thời gian hơn cần thiết để người dùng đóng thành phần. Trình subscribe()xử lý sẽ vẫn được gọi ngay cả khi thành phần bị đóng và bị hủy. Điều này có thể gây ra các tác dụng phụ không mong muốn và trong các trường hợp xấu hơn, trạng thái ứng dụng sẽ bị hỏng. Nó cũng có thể gây ra ngoại lệ nếu mã trong lệnh gọi lại cố gắng gọi một thứ gì đó vừa bị xử lý. Tuy nhiên đồng thời đôi khi chúng được mong muốn. Giống như, giả sử bạn đang tạo ứng dụng email khách và bạn kích hoạt âm thanh khi gửi xong email - bạn vẫn muốn điều đó xảy ra ngay cả khi thành phần đã đóng ( 8 ).
  • Không cần hủy đăng ký khỏi các phần quan sát đã hoàn thành hoặc có lỗi. Tuy nhiên, không có hại gì khi làm như vậy (7) .
  • Sử dụng AsyncPipecàng nhiều càng tốt vì nó tự động hủy đăng ký khỏi sự phá hủy thành phần có thể quan sát được.
  • Hủy đăng ký các thành phần ActivatedRoutecó thể quan sát như route.paramsnếu chúng được đăng ký bên trong một thành phần lồng nhau (Được thêm vào bên trong tpl với bộ chọn thành phần) hoặc thành phần động vì chúng có thể được đăng ký nhiều lần miễn là thành phần chính / máy chủ còn tồn tại. Không cần hủy đăng ký họ trong các trường hợp khác như đã đề cập trong phần trích dẫn ở trên từ Routing & Navigationtài liệu.
  • Hủy đăng ký khỏi các khả năng quan sát chung được chia sẻ giữa các thành phần được hiển thị thông qua một dịch vụ Angular chẳng hạn vì chúng có thể được đăng ký nhiều lần miễn là thành phần được khởi tạo.
  • Không cần hủy đăng ký khỏi các quan sát nội bộ của một dịch vụ trong phạm vi ứng dụng vì dịch vụ này không bao giờ bị phá hủy, trừ khi toàn bộ ứng dụng của bạn bị phá hủy, không có lý do thực sự để hủy đăng ký và không có khả năng bị rò rỉ bộ nhớ. (6) .

    Lưu ý: Đối với các dịch vụ có phạm vi, tức là các nhà cung cấp thành phần, chúng bị hủy khi thành phần bị hủy. Trong trường hợp này, nếu chúng tôi đăng ký bất kỳ nhà cung cấp nào có thể quan sát được bên trong nhà cung cấp này, chúng tôi nên xem xét hủy đăng ký bằng cách sử dụng OnDestroymóc vòng đời sẽ được gọi khi dịch vụ bị hủy, theo tài liệu.
  • Sử dụng một kỹ thuật trừu tượng để tránh bất kỳ sự lộn xộn mã nào có thể phát sinh từ việc hủy đăng ký. Bạn có thể quản lý đăng ký của mình bằng takeUntil (3) hoặc bạn có thể sử dụng npm gói này được đề cập tại (4) Cách dễ nhất để hủy đăng ký khỏi Observables trong Angular .
  • Luôn hủy đăng ký nhận những thứ FormGroupcó thể quan sát được như form.valueChangesform.statusChanges
  • Luôn hủy đăng ký khỏi các Renderer2dịch vụ có thể quan sát được nhưrenderer2.listen
  • Hủy đăng ký mọi đối tượng khác có thể quan sát được như một bước bảo vệ rò rỉ bộ nhớ cho đến khi Angular Docs cho chúng ta biết rõ ràng những đối tượng quan sát nào không cần thiết phải được hủy đăng ký (Kiểm tra sự cố: (5) Tài liệu cho RxJS Hủy đăng ký (Mở) ).
  • Phần thưởng: Luôn sử dụng các cách Angular để liên kết các sự kiện như Angular HostListenerquan tâm tốt đến việc loại bỏ các trình lắng nghe sự kiện nếu cần và ngăn chặn bất kỳ khả năng rò rỉ bộ nhớ nào do các ràng buộc sự kiện.

Mẹo cuối cùng hay : Nếu bạn không biết liệu một cấu kiện có thể quan sát được đang được tự động hủy đăng ký / hoàn thành hay không, hãy thêm một lệnh completegọi lại vào subscribe(...)và kiểm tra xem nó có được gọi khi thành phần bị hủy hay không.

18
Chuanqi Sun 2016-12-01 21:09.

Nó phụ thuộc. Nếu bằng cách gọi someObservable.subscribe(), bạn bắt đầu giữ một số tài nguyên phải được giải phóng thủ công khi vòng đời của thành phần của bạn kết thúc, thì bạn nên gọi theSubscription.unsubscribe()để ngăn rò rỉ bộ nhớ.

Hãy xem xét kỹ hơn các ví dụ của bạn:

getHero()trả về kết quả của http.get(). Nếu bạn xem xét mã nguồn góc 2 , hãy http.get()tạo hai trình nghe sự kiện:

_xhr.addEventListener('load', onLoad);
_xhr.addEventListener('error', onError);

và bằng cách gọi unsubscribe(), bạn cũng như người nghe có thể hủy yêu cầu:

_xhr.removeEventListener('load', onLoad);
_xhr.removeEventListener('error', onError);
_xhr.abort();

Lưu ý rằng đó _xhrlà nền tảng cụ thể nhưng tôi nghĩ rằng có thể an toàn khi cho rằng đó là XMLHttpRequest()trường hợp của bạn.

Thông thường, đây là bằng chứng đủ để đảm bảo một unsubscribe()cuộc gọi thủ công. Nhưng theo thông số CÁI GÌ này , XMLHttpRequest()đối tượng sẽ được thu gom rác một khi nó được "hoàn thành", ngay cả khi có người nghe sự kiện gắn liền với nó. Vì vậy, tôi đoán đó là lý do tại sao hướng dẫn chính thức góc 2 bỏ qua unsubscribe()và để GC dọn dẹp người nghe.

Đối với ví dụ thứ hai của bạn, nó phụ thuộc vào việc triển khai params. Kể từ hôm nay, hướng dẫn chính thức góc cạnh không còn hiển thị việc hủy đăng ký params. Tôi đã xem xét lại src và thấy rằng đó paramschỉ là một BehaviorSubject . Vì không có trình xử lý sự kiện hoặc bộ định thời nào được sử dụng và không có biến toàn cục nào được tạo, nên có thể an toàn khi bỏ qua unsubscribe().

Điểm mấu chốt cho câu hỏi của bạn là luôn gọi unsubscribe()như một biện pháp bảo vệ chống rò rỉ bộ nhớ, trừ khi bạn chắc chắn rằng việc thực thi các biến có thể quan sát được không tạo ra các biến toàn cục, thêm trình xử lý sự kiện, đặt bộ hẹn giờ hoặc làm bất cứ điều gì khác dẫn đến rò rỉ bộ nhớ .

Khi nghi ngờ, hãy xem xét việc thực hiện điều đó có thể quan sát được. Nếu hàm có thể quan sát đã viết một số logic dọn dẹp vào của nó unsubscribe(), thường là hàm được trả về bởi hàm tạo, thì bạn có lý do chính đáng để xem xét nghiêm túc việc gọi unsubscribe().

7
Cerny 2016-06-30 01:08.

Tài liệu chính thức của Angular 2 cung cấp lời giải thích khi nào nên hủy đăng ký và khi nào có thể bỏ qua nó một cách an toàn. Có một liên kết tốt:

https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Tìm đoạn văn có tiêu đề Cha mẹ và con cái giao tiếp qua một dịch vụ và sau đó chọn hộp màu xanh lam:

Lưu ý rằng chúng tôi nắm bắt đăng ký và hủy đăng ký khi AstronautComponent bị phá hủy. Đây là bước bảo vệ rò rỉ bộ nhớ. Không có rủi ro thực tế nào trong ứng dụng này vì thời gian tồn tại của AstronautComponent giống như thời gian tồn tại của chính ứng dụng. Điều đó không phải lúc nào cũng đúng trong một ứng dụng phức tạp hơn.

Chúng tôi không thêm bảo vệ này vào MissionControlComponent vì với tư cách là cha mẹ, nó kiểm soát thời gian tồn tại của MissionService.

Tôi hy vọng cái này sẽ giúp bạn.

6
JoG 2017-04-13 01:04.

Dựa trên: Sử dụng kế thừa Lớp để kết nối với vòng đời của thành phần Angular 2

Một cách tiếp cận chung khác:

export abstract class UnsubscribeOnDestroy implements OnDestroy {
  protected d$: Subject<any>;

  constructor() {
    this.d$ = new Subject<void>();

    const f = this.ngOnDestroy;
    this.ngOnDestroy = () => {
      f();
      this.d$.next();
      this.d$.complete();
    };
  }

  public ngOnDestroy() {
    // no-op
  }

}

Và sử dụng :

@Component({
    selector: 'my-comp',
    template: ``
})
export class RsvpFormSaveComponent extends UnsubscribeOnDestroy implements OnInit {

    constructor() {
        super();
    }

    ngOnInit(): void {
      Observable.of('bla')
      .takeUntil(this.d$)
      .subscribe(val => console.log(val));
    }
}

4
Richard Matsen 2017-05-17 13:06.

Câu trả lời chính thức của Chỉnh sửa số 3 (và các biến thể) hoạt động tốt, nhưng điều khiến tôi chú ý là 'sự xáo trộn' của logic kinh doanh xung quanh đăng ký có thể quan sát được.

Đây là một cách tiếp cận khác bằng cách sử dụng trình bao bọc.

Warining: mã thử nghiệm

File subscribeAndGuard.ts được sử dụng để tạo một phần mở rộng có thể quan sát mới để bọc .subscribe()và bên trong nó để bọc ngOnDestroy().
Cách sử dụng giống như .subscribe(), ngoại trừ một tham số đầu tiên bổ sung tham chiếu đến thành phần.

import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';

const subscribeAndGuard = function(component, fnData, fnError = null, fnComplete = null) {

  // Define the subscription
  const sub: Subscription = this.subscribe(fnData, fnError, fnComplete);

  // Wrap component's onDestroy
  if (!component.ngOnDestroy) {
    throw new Error('To use subscribeAndGuard, the component must implement ngOnDestroy');
  }
  const saved_OnDestroy = component.ngOnDestroy;
  component.ngOnDestroy = () => {
    console.log('subscribeAndGuard.onDestroy');
    sub.unsubscribe();
    // Note: need to put original back in place
    // otherwise 'this' is undefined in component.ngOnDestroy
    component.ngOnDestroy = saved_OnDestroy;
    component.ngOnDestroy();

  };

  return sub;
};

// Create an Observable extension
Observable.prototype.subscribeAndGuard = subscribeAndGuard;

// Ref: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
declare module 'rxjs/Observable' {
  interface Observable<T> {
    subscribeAndGuard: typeof subscribeAndGuard;
  }
}

Đây là một thành phần có hai đăng ký, một có trình bao bọc và một không có. Cảnh báo duy nhất là nó phải thực hiện OnDestroy (với phần thân trống nếu muốn), nếu không Angular không biết gọi phiên bản được bọc.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import './subscribeAndGuard';

@Component({
  selector: 'app-subscribing',
  template: '<h3>Subscribing component is active</h3>',
})
export class SubscribingComponent implements OnInit, OnDestroy {

  ngOnInit() {

    // This subscription will be terminated after onDestroy
    Observable.interval(1000)
      .subscribeAndGuard(this,
        (data) => { console.log('Guarded:', data); },
        (error) => { },
        (/*completed*/) => { }
      );

    // This subscription will continue after onDestroy
    Observable.interval(1000)
      .subscribe(
        (data) => { console.log('Unguarded:', data); },
        (error) => { },
        (/*completed*/) => { }
      );
  }

  ngOnDestroy() {
    console.log('SubscribingComponent.OnDestroy');
  }
}

Một plunker demo ở đây

Một lưu ý bổ sung: Chỉnh sửa lại 3 - Giải pháp 'Chính thức', điều này có thể được đơn giản hóa bằng cách sử dụng takeWhile () thay vì takeUntil () trước khi đăng ký và một boolean đơn giản hơn là một Observable khác trong ngOnDestroy.

@Component({...})
export class SubscribingComponent implements OnInit, OnDestroy {

  iAmAlive = true;
  ngOnInit() {

    Observable.interval(1000)
      .takeWhile(() => { return this.iAmAlive; })
      .subscribe((data) => { console.log(data); });
  }

  ngOnDestroy() {
    this.iAmAlive = false;
  }
}
3
Val 2017-04-24 18:30.

Vì giải pháp của seangwright (Chỉnh sửa 3) tỏ ra rất hữu ích, tôi cũng thấy hơi phiền khi đóng gói tính năng này vào thành phần cơ sở và gợi ý các thành viên khác của dự án nhớ gọi super () trên ngOnDestroy để kích hoạt tính năng này.

Câu trả lời này cung cấp một cách để giải phóng khỏi cuộc gọi siêu cấp và biến "componentDestroyed $" trở thành lõi của thành phần cơ sở.

class BaseClass {
    protected componentDestroyed$: Subject<void> = new Subject<void>();
    constructor() {

        /// wrap the ngOnDestroy to be an Observable. and set free from calling super() on ngOnDestroy.
        let _$ = this.ngOnDestroy;
        this.ngOnDestroy = () => {
            this.componentDestroyed$.next();
            this.componentDestroyed$.complete();
            _$();
        }
    }

    /// placeholder of ngOnDestroy. no need to do super() call of extended class.
    ngOnDestroy() {}
}

Và sau đó bạn có thể sử dụng tính năng này một cách tự do, ví dụ:

@Component({
    selector: 'my-thing',
    templateUrl: './my-thing.component.html'
})
export class MyThingComponent extends BaseClass implements OnInit, OnDestroy {
    constructor(
        private myThingService: MyThingService,
    ) { super(); }

    ngOnInit() {
        this.myThingService.getThings()
            .takeUntil(this.componentDestroyed$)
            .subscribe(things => console.log(things));
    }

    /// optional. not a requirement to implement OnDestroy
    ngOnDestroy() {
        console.log('everything works as intended with or without super call');
    }

}
3
Mau Muñoz 2018-04-20 13:34.

Sau câu trả lời của @seangwright , tôi đã viết một lớp trừu tượng xử lý các đăng ký của các đối tượng quan sát "vô hạn" trong các thành phần:

import { OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import { PartialObserver } from 'rxjs/Observer';

export abstract class InfiniteSubscriberComponent implements OnDestroy {
  private onDestroySource: Subject<any> = new Subject();

  constructor() {}

  subscribe(observable: Observable<any>): Subscription;

  subscribe(
    observable: Observable<any>,
    observer: PartialObserver<any>
  ): Subscription;

  subscribe(
    observable: Observable<any>,
    next?: (value: any) => void,
    error?: (error: any) => void,
    complete?: () => void
  ): Subscription;

  subscribe(observable: Observable<any>, ...subscribeArgs): Subscription {
    return observable
      .takeUntil(this.onDestroySource)
      .subscribe(...subscribeArgs);
  }

  ngOnDestroy() {
    this.onDestroySource.next();
    this.onDestroySource.complete();
  }
}

Để sử dụng nó, chỉ cần mở rộng nó trong thành phần góc cạnh của bạn và gọi subscribe()phương thức như sau:

this.subscribe(someObservable, data => doSomething());

Nó cũng chấp nhận lỗi và hoàn thành các cuộc gọi lại như bình thường, một đối tượng quan sát, hoặc hoàn toàn không gọi lại. Hãy nhớ gọi super.ngOnDestroy()nếu bạn cũng đang triển khai phương thức đó trong thành phần con.

Tìm ở đây một tài liệu tham khảo bổ sung của Ben Lesh: RxJS: Đừng hủy đăng ký .

2
Jeff Tham 2017-04-12 10:00.

Tôi đã thử giải pháp của seangwright (Chỉnh sửa 3)

Điều đó không hoạt động đối với Observable được tạo bởi bộ đếm thời gian hoặc khoảng thời gian.

Tuy nhiên, tôi đã làm cho nó hoạt động bằng cách sử dụng một cách tiếp cận khác:

import { Component, OnDestroy, OnInit } from '@angular/core';
import 'rxjs/add/operator/takeUntil';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/Rx';

import { MyThingService } from '../my-thing.service';

@Component({
   selector: 'my-thing',
   templateUrl: './my-thing.component.html'
})
export class MyThingComponent implements OnDestroy, OnInit {
   private subscriptions: Array<Subscription> = [];

  constructor(
     private myThingService: MyThingService,
   ) { }

  ngOnInit() {
    const newSubs = this.myThingService.getThings()
        .subscribe(things => console.log(things));
    this.subscriptions.push(newSubs);
  }

  ngOnDestroy() {
    for (const subs of this.subscriptions) {
      subs.unsubscribe();
   }
 }
}
2
Scott Williams 2017-04-27 07:58.

Tôi thích hai câu trả lời cuối cùng, nhưng tôi đã gặp sự cố nếu lớp con được tham chiếu "this"trong ngOnDestroy.

Tôi đã sửa đổi nó thành cái này và có vẻ như nó đã giải quyết được vấn đề đó.

export abstract class BaseComponent implements OnDestroy {
    protected componentDestroyed$: Subject<boolean>;
    constructor() {
        this.componentDestroyed$ = new Subject<boolean>();
        let f = this.ngOnDestroy;
        this.ngOnDestroy = function()  {
            // without this I was getting an error if the subclass had
            // this.blah() in ngOnDestroy
            f.bind(this)();
            this.componentDestroyed$.next(true);
            this.componentDestroyed$.complete();
        };
    }
    /// placeholder of ngOnDestroy. no need to do super() call of extended class.
    ngOnDestroy() {}
}
2
Alireza 2017-10-17 01:52.

Bạn thường cần hủy đăng ký khi các thành phần bị phá hủy, nhưng Angular sẽ xử lý nó ngày càng nhiều hơn khi chúng ta tiếp tục, ví dụ như trong phiên bản nhỏ mới của Angular4, họ có phần này để định tuyến hủy đăng ký:

Bạn có cần phải hủy đăng ký không?

Như được mô tả trong ActivateRoute: phần một cửa cho thông tin tuyến đường của trang Định tuyến & Điều hướng, Bộ định tuyến quản lý các thiết bị có thể quan sát được mà nó cung cấp và bản địa hóa các đăng ký. Các đăng ký được dọn dẹp khi thành phần bị phá hủy, bảo vệ khỏi rò rỉ bộ nhớ, vì vậy bạn không cần phải hủy đăng ký khỏi route paramMap Observable.

Ngoài ra, ví dụ dưới đây là một ví dụ điển hình từ Angular để tạo một thành phần và phá hủy nó sau đó, hãy xem cách thành phần triển khai OnDestroy, nếu bạn cần onInit, bạn cũng có thể triển khai nó trong thành phần của mình, như các công cụ OnInit, OnDestroy

import { Component, Input, OnDestroy } from '@angular/core';  
import { MissionService } from './mission.service';
import { Subscription }   from 'rxjs/Subscription';

@Component({
  selector: 'my-astronaut',
  template: `
    <p>
      {{astronaut}}: <strong>{{mission}}</strong>
      <button
        (click)="confirm()"
        [disabled]="!announced || confirmed">
        Confirm
      </button>
    </p>
  `
})

export class AstronautComponent implements OnDestroy {
  @Input() astronaut: string;
  mission = '<no mission announced>';
  confirmed = false;
  announced = false;
  subscription: Subscription;

  constructor(private missionService: MissionService) {
    this.subscription = missionService.missionAnnounced$.subscribe(
      mission => {
        this.mission = mission;
        this.announced = true;
        this.confirmed = false;
    });
  }

  confirm() {
    this.confirmed = true;
    this.missionService.confirmMission(this.astronaut);
  }

  ngOnDestroy() {
    // prevent memory leak when component destroyed
    this.subscription.unsubscribe();
  }
}
2
Oleg Polezky 2019-02-21 05:07.

Trong trường hợp cần hủy đăng ký, có thể sử dụng toán tử sau cho phương pháp đường ống quan sát được

import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { OnDestroy } from '@angular/core';

export const takeUntilDestroyed = (componentInstance: OnDestroy) => <T>(observable: Observable<T>) => {
  const subjectPropertyName = '__takeUntilDestroySubject__';
  const originalOnDestroy = componentInstance.ngOnDestroy;
  const componentSubject = componentInstance[subjectPropertyName] as Subject<any> || new Subject();

  componentInstance.ngOnDestroy = (...args) => {
    originalOnDestroy.apply(componentInstance, args);
    componentSubject.next(true);
    componentSubject.complete();
  };

  return observable.pipe(takeUntil<T>(componentSubject));
};

nó có thể được sử dụng như thế này:

import { Component, OnDestroy, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

@Component({ template: '<div></div>' })
export class SomeComponent implements OnInit, OnDestroy {

  ngOnInit(): void {
    const observable = Observable.create(observer => {
      observer.next('Hello');
    });

    observable
      .pipe(takeUntilDestroyed(this))
      .subscribe(val => console.log(val));
  }

  ngOnDestroy(): void {
  }
}

Toán tử kết thúc phương thức ngOnDestroy của thành phần.

Quan trọng: người vận hành phải là người cuối cùng trong đường ống có thể quan sát được.

1
Krishna Ganeriwal 2018-06-17 02:49.

Một bổ sung ngắn khác cho các tình huống được đề cập ở trên là:

  • Luôn hủy đăng ký, khi các giá trị mới trong luồng đã đăng ký không cần thiết nữa hoặc không quan trọng, điều đó sẽ dẫn đến số lượng trình kích hoạt ít hơn và tăng hiệu suất trong một số trường hợp. Các trường hợp như các thành phần trong đó dữ liệu / sự kiện đã đăng ký không còn tồn tại nữa hoặc yêu cầu đăng ký mới cho một luồng hoàn toàn mới (làm mới, v.v.) là một ví dụ điển hình cho việc hủy đăng ký.
1
Wilt 2020-03-01 23:33.

Đối với các phần có thể quan sát hoàn thành trực tiếp sau khi đưa ra kết quả như AsyncSubjecthoặc ví dụ các phần có thể quan sát từ các yêu cầu http và như vậy bạn không cần phải hủy đăng ký. Không hại gì khi gọi unsubscribe()những thứ đó, nhưng nếu điều quan sát được là closedphương pháp hủy đăng ký sẽ đơn giản là không làm được gì :

if (this.closed) {
  return;
}

Khi bạn có các vật thể quan sát tồn tại lâu dài phát ra một số giá trị theo thời gian (như ví dụ: a BehaviorSubjecthoặc a ReplaySubject), bạn cần hủy đăng ký để tránh rò rỉ bộ nhớ.

Bạn có thể dễ dàng tạo một vật có thể quan sát hoàn thành trực tiếp sau khi đưa ra kết quả từ các vật thể quan sát tồn tại lâu như vậy bằng cách sử dụng một toán tử ống. Trong một số câu trả lời ở đây, take(1)đường ống được đề cập. Nhưng tôi thích các first()ống . Sự khác biệt take(1)là nó sẽ:

gửi một EmptyErrorlệnh gọi lại lỗi của Người quan sát nếu Người quan sát hoàn tất trước khi bất kỳ thông báo tiếp theo nào được gửi đi.

Một ưu điểm khác của đường ống đầu tiên là bạn có thể chuyển một vị từ sẽ giúp bạn trả về giá trị đầu tiên đáp ứng các tiêu chí nhất định:

const predicate = (result: any) => { 
  // check value and return true if it is the result that satisfies your needs
  return true;
}
observable.pipe(first(predicate)).subscribe(observer);

First sẽ hoàn thành trực tiếp sau khi tạo ra giá trị đầu tiên (hoặc khi truyền một đối số hàm giá trị đầu tiên thỏa mãn vị từ của bạn) nên không cần hủy đăng ký.

Đôi khi bạn không chắc chắn về việc bạn có thể quan sát được lâu hay không. Tôi không nói đó là phương pháp hay nhưng sau đó, bạn luôn có thể thêm firstđường ống chỉ để đảm bảo rằng bạn sẽ không cần phải hủy đăng ký theo cách thủ công. Việc thêm một firstđường ống bổ sung trên một thiết bị có thể quan sát sẽ chỉ phát ra một giá trị không ảnh hưởng gì.

Trong phát triển, bạn có thể sử dụng các singleống đó sẽ thất bại nếu nguồn phát ra quan sát được một số sự kiện. Điều này có thể giúp bạn khám phá loại có thể quan sát được và liệu có cần thiết phải hủy đăng ký hay không.

observable.pipe(single()).subscribe(observer);

Các firstsingledường như rất giống nhau, cả hai đường ống có thể mất một vị ngữ bắt buộc nhưng sự khác biệt rất quan trọng và độc đáo tóm tắt trong stackoverflow câu trả lời này đây :

Đầu tiên

Sẽ phát ra ngay khi mục đầu tiên xuất hiện. Sẽ hoàn thành ngay sau đó.

Độc thân

Sẽ thất bại nếu nguồn có thể quan sát phát ra một số sự kiện.


Lưu ý rằng tôi đã cố gắng hoàn thiện chính xác và đầy đủ nhất có thể trong câu trả lời của mình với các tham chiếu đến tài liệu chính thức, nhưng vui lòng nhận xét nếu thiếu điều gì quan trọng ...

0
mojtaba ramezani 2019-04-19 18:50.

trong ứng dụng SPA tại chức năng ngOnDestroy (Vòng đời góc cạnh) Đối với mỗi đăng ký, bạn cần hủy đăng ký . thuận lợi => để tránh tình trạng trở nên quá nặng.

ví dụ: trong component1:

import {UserService} from './user.service';

private user = {name: 'test', id: 1}

constructor(public userService: UserService) {
    this.userService.onUserChange.next(this.user);
}

phục vụ:

import {BehaviorSubject} from 'rxjs/BehaviorSubject';

public onUserChange: BehaviorSubject<any> = new BehaviorSubject({});

trong component2:

import {Subscription} from 'rxjs/Subscription';
import {UserService} from './user.service';

private onUserChange: Subscription;

constructor(public userService: UserService) {
    this.onUserChange = this.userService.onUserChange.subscribe(user => {
        console.log(user);
    });
}

public ngOnDestroy(): void {
    // note: Here you have to be sure to unsubscribe to the subscribe item!
    this.onUserChange.unsubscribe();
}
0
Pratiyush 2019-05-21 00:33.

Để xử lý đăng ký, tôi sử dụng lớp "Người hủy đăng ký".

Đây là Lớp chưa đăng ký.

export class Unsubscriber implements OnDestroy {
  private subscriptions: Subscription[] = [];

  addSubscription(subscription: Subscription | Subscription[]) {
    if (Array.isArray(subscription)) {
      this.subscriptions.push(...subscription);
    } else {
      this.subscriptions.push(subscription);
    }
  }

  unsubscribe() {
    this.subscriptions
      .filter(subscription => subscription)
      .forEach(subscription => {
        subscription.unsubscribe();
      });
  }

  ngOnDestroy() {
    this.unsubscribe();
  }
}

Và Bạn có thể sử dụng lớp này trong bất kỳ thành phần / Dịch vụ / Hiệu ứng nào, v.v.

Thí dụ:

class SampleComponent extends Unsubscriber {
    constructor () {
        super();
    }

    this.addSubscription(subscription);
}
0
ganesh045 2019-09-09 21:15.

Bạn có thể sử dụng Subscriptionlớp mới nhất để hủy đăng ký Observable với mã không quá lộn xộn.

Chúng tôi có thể làm điều này với normal variablenhưng nó sẽ có override the last subscriptiontrên mỗi đăng ký mới, vì vậy hãy tránh điều đó và cách tiếp cận này rất hữu ích khi bạn đang xử lý số lượng Obseravables nhiều hơn và loại Obeservables như BehavoiurSubjectSubject

Đăng ký

Đại diện cho một tài nguyên dùng một lần, chẳng hạn như việc thực thi một Observable. Đăng ký có một phương pháp quan trọng, hủy đăng ký, không cần tranh cãi và chỉ hủy tài nguyên do đăng ký nắm giữ.

bạn có thể sử dụng điều này theo hai cách,

  • bạn có thể trực tiếp đẩy đăng ký vào Mảng đăng ký

     subscriptions:Subscription[] = [];
    
     ngOnInit(): void {
    
       this.subscription.push(this.dataService.getMessageTracker().subscribe((param: any) => {
                //...  
       }));
    
       this.subscription.push(this.dataService.getFileTracker().subscribe((param: any) => {
            //...
        }));
     }
    
     ngOnDestroy(){
        // prevent memory leak when component destroyed
        this.subscriptions.forEach(s => s.unsubscribe());
      }
    
  • sử dụng add()củaSubscription

    subscriptions = new Subscription();
    
    this.subscriptions.add(subscribeOne);
    this.subscriptions.add(subscribeTwo);
    
    ngOnDestroy() {
      this.subscriptions.unsubscribe();
    }
    

A Subscriptioncó thể giữ các đăng ký của trẻ em và hủy đăng ký tất cả chúng một cách an toàn. Phương pháp này xử lý các lỗi có thể xảy ra (ví dụ: nếu bất kỳ đăng ký con nào là trống).

Hi vọng điêu nay co ich.. :)

0
SnorreDan 2020-02-02 22:59.

Gói SubSink, một giải pháp dễ dàng và nhất quán để hủy đăng ký

Vì chưa ai đề cập đến nó, tôi muốn giới thiệu gói Liên kết đăng ký do Ward Bell tạo: https://github.com/wardbell/subsink#readme .

Tôi đã sử dụng nó trong một dự án mà chúng tôi là một số nhà phát triển đều đang sử dụng nó. Nó giúp ích rất nhiều để có một cách nhất quán hoạt động trong mọi tình huống.

0
Yogesh Waghmare 2020-07-23 23:56.

Một Đăng ký về cơ bản chỉ có một hàm unsubscribe () để giải phóng tài nguyên hoặc hủy bỏ các thực thi có thể quan sát được. Trong Angular, chúng ta phải hủy đăng ký Observable khi thành phần đang bị phá hủy. May mắn thay, Angular có một hook ngOnDestroy được gọi trước khi một thành phần bị phá hủy, điều này cho phép các nhà phát triển cung cấp nhóm dọn dẹp ở đây để tránh treo đăng ký, mở cổng và những thứ không hay có thể xảy ra trong tương lai sẽ cắn chúng ta

@Component({...})
export class AppComponent implements OnInit, OnDestroy {
    subscription: Subscription 
    ngOnInit () {
        var observable = Rx.Observable.interval(1000);
        this.subscription = observable.subscribe(x => console.log(x));
    }
    ngOnDestroy() {
        this.subscription.unsubscribe()
    }
}

Chúng tôi đã thêm ngOnDestroy vào AppCompoennt của mình và gọi phương thức hủy đăng ký trên this.subscription Observable

Nếu có nhiều đăng ký:

@Component({...})
export class AppComponent implements OnInit, OnDestroy {
    subscription1$: Subscription
    subscription2$: Subscription 
    ngOnInit () {
        var observable1$ = Rx.Observable.interval(1000);
        var observable2$ = Rx.Observable.interval(400);
        this.subscription1$ = observable.subscribe(x => console.log("From interval 1000" x));
        this.subscription2$ = observable.subscribe(x => console.log("From interval 400" x));
    }
    ngOnDestroy() {
        this.subscription1$.unsubscribe()
        this.subscription2$.unsubscribe()
    }
}

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Các luật sư của Trump muốn vụ kiện Stormy Daniels được giải quyết trước mắt công chúng

Các luật sư của Trump muốn vụ kiện Stormy Daniels được giải quyết trước mắt công chúng

Ảnh: Getty Nếu có vẻ như câu chuyện Stormy Daniels-Donald Trump là một trò chơi bất tận giữa các luật sư (một số người trong số họ rất ngu ngốc), đó là bởi vì nó là. Vào thứ Hai, các luật sư đại diện cho luật sư của Trump, Michael Cohen và Trump đã thực hiện vở kịch mới nhất của họ: một đề nghị để vụ việc được quyết định bởi một trọng tài riêng.

Colin Trevorrow sẽ trở lại để chỉ đạo phần ba của phim thế giới kỷ Jura

Colin Trevorrow sẽ trở lại để chỉ đạo phần ba của phim thế giới kỷ Jura

Chris Pratt và Colin Trevorrow trên phim trường Jurassic World. Người đàn ông đầu tiên mạo hiểm vào Thế giới kỷ Jura sẽ trở lại đó cho phần cuối của bộ ba.

Bạn sẽ phân biệt chủng tộc như thế nào nếu người da đen thực sự có thể phân biệt chủng tộc?

Bạn sẽ phân biệt chủng tộc như thế nào nếu người da đen thực sự có thể phân biệt chủng tộc?

Một trong những điều thất vọng lớn nhất trong cuộc đời tôi - có lẽ thực sự là thất vọng lớn nhất - là người da đen ở Mỹ không có khả năng phân biệt chủng tộc. Chúng ta có thể cố gắng hết sức và ghét nhất có thể, nhưng do cách thức hoạt động của chủ nghĩa phân biệt chủng tộc, chúng ta sẽ không bao giờ có thể sử dụng tình trạng được săn đón là “phân biệt chủng tộc.

Bạn không cần phải xả những củ khoai tây nghiền này ngay lập tức

Bạn không cần phải xả những củ khoai tây nghiền này ngay lập tức

Một trong những thứ yêu thích của tôi để nấu trong Instant Pot (hoặc bất kỳ nồi áp suất nào) là các loại rau củ, nếu không sẽ mất nhiều thời gian hơn. Khoai tây chắc chắn thuộc loại này, đặc biệt là vì bạn có thể làm khoai tây nghiền hoàn toàn như kem hoàn toàn trong Nồi ăn liền mà không cần xả nước.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Đường băng hạ cánh

Đường băng hạ cánh

Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Language