即使在组件破坏后,仍可订阅对服务可观察的请求

时间:2019-02-25 10:05:51

标签: angular service observable provider

我在服务中遇到了可观察的问题。以下代码说明了这一点:

@Injectable({
  providedIn: 'root'
})
export class MyService {
  public globalVariable: BehaviorSubject<string> = new BehaviorSubject('');
}

我有一个功能部件:

export class ComponentA implements OnInit {
   constructor(public myService : MyService ) {
      this.myService.globalVariable.next('newValue');
   }

   ngOnInit() {
      this.myService.globalVariable.subscribe(_ => console.log('=> hello'));
   }
}

应用模块:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ComponentAModule,
    ComponentBModule,
    AppRoutingModule
  ],
  providers: [MyService],
  bootstrap: [AppComponent]
})
export class AppModule {
}

最后是项目结构:

app-module.ts
app-routing.module.ts
-components
-- componentA
--- componentA.module.ts
--- componentA-routing.module.ts
--- componentA.component.ts
--- componentA.component.html
-- componentB
--- componentB.module.ts
--- componentB-routing.module.ts
--- componentB.component.ts
--- componentB.component.html

现在面临的问题是,当我导航到componentA时,输出为:

=> hello
=> hello

直到现在,一切都正常,并且表现出预期。触发第一个订阅,然后由globalVariable的构造函数在componentA中进行更改。

但是,当我导航至componentB并返回至componentA时,输出为:

=> hello
=> hello
=> hello

每当我导航回componentA时,它就会添加一个。好像它创建了MyService的新实例?还是在离开时不破坏订阅?

信息:没有延迟加载。

3 个答案:

答案 0 :(得分:1)

您需要在arrays$count = 0; foreach($checkboxfiles as $checkboxfile) { $src_file = $checkboxfile; $fileName = basename($src_file); $new_dest = $_POST['cbdestination']; /* New path for this file */ $dest_file = $MainFolderName.'/'. $new_dest . '/' . $fileName; if(file_exists($dest_file)){ $count++; } } echo $count;

unsubscribe

答案 1 :(得分:1)

如果订阅不是由Angular自己处理的,则必须手动销毁它们。这基本上适用于您拥有的所有httpClient订阅。如果您例如使用| async管道,Angular会取消订阅。

在组件的yourSubscription.unsubscribe()中调用ngOnDestroy()

我通常要做的是创建一个BaseComponent来替我取消订阅。通过扩展在所有组件中使用下面的类。将每个订阅呼叫都包装在super.addSubscription()

import { OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

/**
 * This class handles the subscribing and unsubscribing of subscriptions to avoid memory leaks
 * and can be inherited by members
 *
 * @export
 */
export abstract class BaseComponent implements OnDestroy {

private subscriptions: Subscription[] = new Array<Subscription>();

ngOnDestroy() {
    this.removeSubscriptions();
}

/**
 * Adds a subscriptions so it can be deleted in ngOnDestroy
 *
 * @param subscription The subscription that should be added
 * @memberof BaseComponent
 */
protected addSubscription(subscription: Subscription) {
    this.subscriptions.push(subscription);
}

/**
 * Unsubscribes from any open subscriptions in the subscriptions array in ngOnDestroy
 *
 * @memberof AbstractBaseComponent
 */
private removeSubscriptions() {
    for (let subscription of this.subscriptions) {
        subscription.unsubscribe();
    }
}
}

更新

假设您使用上面提供的基类,请对您的ngOnInit()执行以下操作:

export class ComponentA extends BaseComponent implements OnInit {
    constructor(public myService : MyService ) {
       this.myService.globalVariable.next('newValue');
    }
    ngOnInit() {
       super.addSubscription(
           this.myService.globalVariable.subscribe(_ => console.log('=> hello'))
       )
    }
}

答案 2 :(得分:0)

如果要使用订阅管道而不是异步管道,则可以使用RxJs运算符takeWhile。请参见下面的代码...

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit, OnDestroy {
  name = 'Angular';
  isActive: boolean;
  // returned from service.  Does not need to initialized here
  thingToSubscribeTo:Observable<any> = new Observable<any>();

  ngOnInit() {
    this.isActive = true;
    // you can replace with call to service then pipe it.
    this.thingToSubscribeTo.pipe(
      map(res => {
        // handle subscription
      }),
      takeWhile(() => this.isActive)
    );

  }

  ngOnDestroy() {
    this.isActive = false;
  }
}