2017-08-16 51 views
3

我這裏有分量的代碼,當我訂閱了觀察到的服務被調用了兩次,但是如果我訂閱Behaviorsubject它只能觸發一次,爲什麼服務在這個角度2分量中調用兩次?

我可以在我的日誌,那些是結果看,請查看我的代碼,下面是我的組件 在ngOninit上調用subscribeToMap()方法的方法。

import { Component, OnInit } from '@angular/core'; 
import { Router }   from '@angular/router'; 

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

// Observable class extensions 
import 'rxjs/add/observable/of'; 

// Observable operators 
import 'rxjs/add/operator/catch'; 
import 'rxjs/add/operator/debounceTime'; 
import 'rxjs/add/operator/distinctUntilChanged'; 

import { HeroSearchService } from './hero-search-service'; 
import { Hero } from './../hero'; 

@Component({ 
    selector: 'hero-search', 
    templateUrl: './hero-search.component.html', 
    styleUrls: [ './hero-search.component.css' ], 
    providers: [HeroSearchService] 
}) 
export class HeroSearchComponent implements OnInit { 
    heroes: Observable<Hero[]>; 
    private searchTerms = new Subject<string>(); 

    constructor(
    private heroSearchService: HeroSearchService, 
    private router: Router) {} 

    // Push a search term into the observable stream. 
    search(term: string): void { 
    this.searchTerms.next(term); 
    console.log("new " + term); 
    } 



    ngOnInit(): void { 
    this.heroes = this.searchTerms 
     .debounceTime(300)  // wait 300ms after each keystroke before considering the term 
     .distinctUntilChanged() // ignore if next search term is same as previous 
     .switchMap(term => { 
     return term // switch to new observable each time the term changes 
     // return the http search observable 
     ? this.heroSearchService.search(term) 
     // or the observable of empty heroes if there was no search term 
     : Observable.of<Hero[]>([])}) 
     .catch(error => { 
     // TODO: add real error handling 
     console.log(error); 
     return Observable.of<Hero[]>([]); 
     }); 
     this.subscribeToMap(); 
    } 

    subscribeToMap(): void{ 
    this.heroes.subscribe(() => console.log("called twice")); 
    this.searchTerms.subscribe(() => console.log("called once")); 
    } 


    gotoDetail(hero: Hero): void { 
    let link = ['/detail', hero.id]; 
    this.router.navigate(link); 
    } 
} 

這裏是代碼爲我服務

import { Injectable } from '@angular/core'; 
import { Http }  from '@angular/http'; 

import { Observable }  from 'rxjs/Observable'; 
import 'rxjs/add/operator/map'; 

import { Hero }   from './../hero'; 

@Injectable() 
export class HeroSearchService { 

    constructor(private http: Http) {} 

    search(term: string): Observable<Hero[]> { 
    console.log("service is called"); 
    return this.http 
       .get(`api/heroes/?name=${term}`) 
       .map(response => response.json().data as Hero[]); 
    } 
} 

謝謝版本多!

+0

你可以創建一個相同的plunker?你打電話訂閱ngOnInit –

+0

@RahulSingh我知道,ngonit被觸發一次,唯一的辦法是訂閱。 :) –

+0

我試圖調試你的代碼,以找到一個答案,爲什麼被擊兩次,代碼將在'.switchMap'上打破。將有助於說明如何在組件上調用search(),當改變searchTerms時可能會觸發。如果有人想從這裏拿走,我已經在這裏做了一個[plunker](https://plnkr.co/edit/Acedx2qldUj9fFXKPh3O?p=preview) – BogdanC

回答

1

訂閱正確實現時,它與「取消訂閱」方法,Observable等無關。此行爲是Angular本身的設計。

https://www.reddit.com/r/Angular2/comments/59532r/function_being_called_multiple_times/d95vjlz/

如果你在開發模式下運行時,它將運行功能 至少兩次。因爲在開發模式下,它會執行檢查,更改, 然後重新檢查以驗證,其中生產模式僅執行第一個 檢查,假設您已完成質量保證並且解決了任何 值更改的檢查後檢查。

P.S.這可能是下一個問題,你將面對在開發模式:)

Angular2 change detection "Expression has changed after it was checked"

0

嘗試更換這行:

this.heroes = this.searchTerms 

有了這一個:

this.heroes = this.searchTerms.asObservable() 

確保英雄是可觀察到的,並在它的代碼不會意外調用next()

您的代碼將英雄轉換爲主體,因此您仍然可以對其執行next()。

+0

是的,明白了。但是令我着迷的是,爲什麼服務在訂閱可觀測數據時被調用兩次? –

+0

主題創建一個可與外部共享的內部訂閱。我只能猜測,當您將主題實例分配給訂閱仍然存在的observable時。但這是我瘋狂的猜測:) –