[入门级]angular4学习笔记07

HttpModule

  • HttpModule是Angular用来进行web访问的一种可选的方式,它位于一个名叫@angular/http的独立附属模块中,并作为Angular的npm包之一而发布出来,所以它并不是angular的核心模块

mock服务(InMemoryWebApiModule)

  • 导入InMemoryWebApiModule,并将其加入到模块的imports数组,ImMemoryWebApiModule将Http客服的默认的后端服务替换成了内存Web API服务
InMemoryWebApiModule.forRoot(InMemoryDataService)

forRoot()配置方法需要InMemoryDataService类实例,用来向内存数据库填充数据:往app目录下新增一个文件
in-memory-data.service.ts

import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
  createDb() {
    const heroes = [
      { id: 0,  name: 'Zero' },
      { id: 11, name: 'Mr. Nice' },
      { id: 12, name: 'Narco' },
      { id: 13, name: 'Bombasto' },
      { id: 14, name: 'Celeritas' },
      { id: 15, name: 'Magneta' },
      { id: 16, name: 'RubberMan' },
      { id: 17, name: 'Dynama' },
      { id: 18, name: 'Dr IQ' },
      { id: 19, name: 'Magma' },
      { id: 20, name: 'Tornado' }
    ];
    return {heroes};
  }
}

Http请求

hero.service.ts

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

import 'rxjs/add/operator/toPromise';

import { Hero } from './hero';

private heroesUrl = 'api/heroes';  // URL to web api

constructor(private http: Http) { }

getHeroes(): Promise {
  return this.http.get(this.heroesUrl)
            .toPromise()
            .then(response => response.json() as Hero[])
            .catch(this.handleError);
}
private handleError(error: any): Promise {
  console.error('An error occurred', error); // for demo purposes only
  return Promise.reject(error.message || error);
}

解析

  • Angular的http.get返回一个RxJS的Observable对象,Observable是一个管理异步数据流的强力方式
  • 我们利用toPromise操作符把Observable直接转换成Promise对象
  • Angular的Observable并没有一个toPromise操作符,没有打包在一起发布,Observable只是一个骨架实现,很多向toPromise这样的操作符,用于扩展Observable,为其添加有用的能力,如果我们需要这些能力,就要自己添加那些操作符,只要从RxJS库中导入他们就可以了,例如:
import 'rxjs/add/operator/toPromise';
  • 在promise的then()回调中,我们调用HTTP的Response对象的json方法,以提取其中的数据
  • 在getHeroes()的最后,我们catch了服务器的失败信息,并把它传给了错误处理器
  • 我们要通过一个被拒绝(rejected)的承诺来把该错误用一个用户友好的格式返回给调用者,以便调用者把一个合适的错误信息显示给用户

Observable

  • 请求并非总是“一次性”的,我们可以开始一个请求,并且取消它,在服务器对第一个请求做出回应之前,再开始另一个不同的请求,像这样一个 请求-取消-新请求 的序列用 承诺 是很难实现的,但对Observable来说则很简单

hero-search.service.ts

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 {
    return this.http
               .get(`api/heroes/?name=${term}`)
               .map(response => response.json() as Hero[]);
  }
}

解析:

  • search()方法没有调用toPromise方法,而是从http.get方法中返回一个Observable对象,之后调用RxJS的map操作符 来从返回数据中提取heroes

hero-search.component.html

Hero Search

{{hero.name}}

解析:

  • heroes属性现在是heroes列表的Observable对象,而不再只是heroes数组,ngFor不能用可观察对象做任何事,除非我们在它后面跟一个async pipe(AsyncPipe),这个async管道会订阅到这个可观察对象,并且为ngFor生成一个heroes列表

Subject

hero-search.component.ts

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;
  private searchTerms = new Subject();

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

  // Push a search term into the observable stream.
  search(term: string): void {
    this.searchTerms.next(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 => 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([]))
      .catch(error => {
        // TODO: add real error handling
        console.log(error);
        return Observable.of([]);
      });
  }

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

解析:

  • Subject是一个 可观察的 事件流中的生产者,searchTerms生成一个产生Observable,用作按名称搜索时的过滤条件
  • 每当调用search()时都会调用next()来把新的字符串放进该主题的可观察流中
如果我们直接把每一次用户按键都直接传给HeroSearchService,就会发起一场HTTP请求风暴,这可不好,我们不希望占用服务器的资源,也不想耗光蜂窝移动的网络流量,可以在Observable字符串的后面串联一些Observable操作符,来归并这些请求,我们将对HeroSearchService发起更少的调用,并且仍然获得足够及时的反应
  • 在传出最终字符串之前,debounceTime(300)将会等待,直到新增字符串的事件暂停300毫秒,我们实际发起请求的间隔永远不会小于300ms
  • distinctUntilChanged确保只在过滤条件发生变化时才发送请求,这样就不会重复请求同一个搜索词
  • switchMap()会为每一个从debounceTime和distinctUntilChanged中通过的搜索词调用search服务,它会取消并丢弃以前的搜索可观察对象,只保留最近的
  • catch拦截失败的可观察对象
[入门级]angular4学习笔记07_第1张图片
公众号:前端咖秀

你可能感兴趣的:([入门级]angular4学习笔记07)