【问题标题】:Why is the service called twice in this angular 2 component?为什么这个 angular 2 组件中的服务被调用了两次?
【发布时间】:2017-08-16 15:58:17
【问题描述】:

我这里有组件代码,当我订阅 observable 时,服务会被调用两次,但是如果我订阅 Behaviorsubject 它只会触发一次,

我可以在我的日志中看到这些是结果,请在下面查看我的代码以了解我的组件 方法 subscribeToMap() 方法在 ngOninit 上被调用。

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[]);
  }
}

非常感谢!!!

【问题讨论】:

  • 你可以为它创建一个 plunker 吗?您正在 ngOnInit 上调用 subscribe
  • @RahulSingh 我知道,ngoni 被触发一次,它唯一的作用就是订阅。 :)
  • 我试图调试你的代码以找到为什么被命中两次的答案,代码将在.switchMap 上中断。有助于了解您如何在组件上调用search(),当您更改searchTerms 时可能会有触发器。如果有人想从这里拿走,我已经发了plunker here

标签: javascript angular angular2-services


【解决方案1】:

当订阅被正确实现时,它与“取消订阅”方法、Observable 等无关。这种行为是 Angular 本身的设计。

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

如果您在开发模式下运行,它将运行该功能 至少两次。因为在开发模式下它会进行检查,更改, 然后重新检查以验证,生产模式只做第一个 检查,假设您已经完成了质量保证并解决了任何问题 重视 get changed post 检查。

附:这可能是您在开发模式下将面临的下一个问题 :)

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

【讨论】:

    【解决方案2】:

    尝试替换这一行:

    this.heroes = this.searchTerms
    

    有了这个:

    this.heroes = this.searchTerms.asObservable()
    

    以确保 hero 是可观察的,并且您的代码不会意外地在其上调用 next()

    您的代码将 hero 转换为 Subject,因此您仍然可以对其执行 next()。

    【讨论】:

    • 是的,明白了。但令我着迷的是,为什么订阅 observable 时服务会被调用两次?
    • 主题创建一个内部订阅,它可以与外部订阅共享。我只能猜测,当您将主题实例分配给可观察的对象时,该订阅仍然有效。但这是我的疯狂猜测:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 2013-11-20
    • 2019-10-02
    相关资源
    最近更新 更多