2017-08-16 52 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时。但这是我疯狂的猜测:) –