Angular 官网学习(一)—— 可观察对象 Observable

目录

Observable 基本概念

observer 的三个属性

创建可观察对象(法一:of()、from())

实例练习:创建并订阅一个可观察对象,让它的观察者把接收的消息,记录到控制台中

 创建可观察对象(法二:订阅者函数 sequenceSubscriber)

Observable 捕获错误

可观察对象 是 Angular 中处理 异步操作 的接口

在组件之间传递数据

基于可观察对象(Observable)的 HTTP API

Async 管道

路由器 (router)【存在问题】

响应式表单 (reactive forms)

Observables VS promises

Observables VS  Events API

Observables VS  Array


Observable 基本概念

  • Observable(可观察对象),属于 RxJS库 里的 对象,用来处理 异步事件,例如 HTTP 请求
  • 在 Angular 中,所有的 HTTP 请求 返回的都是 Observable
  • promise 和 Observable 本质上相同:都是生产者主动向消费者 “push” 产品,而消费者是被动接收
  • 两者区别:Observable 可以发送任意多值,且被订阅之前不会执行
  • Observable 用于在发送方和接收方之间传输消息,可以将这些消息看成是 ”流“
  • 创建 Observable 对象时,需要传入 订阅者函数(subscriber)作为构造函数的参数,订阅者函数也就是生产者向消费者推送消息的地方
  • 被消费者subscribe(订阅)之前,订阅者函数不会被执行,直到 subscribe() 函数 被调用,表示 订阅
  • subscribe() 函数接收 observer(观察者)对象 作为参数,观察者 用于 观察可观察对象(发送方)
  • subscribe() 函数返回 subscription 对象,里面有 unsubscribe() 函数,用于消费者随时 取消订阅
  • 消息的发送可以是同步的,也可以是异步的
  • 可以使用 RxJS 操作符,在这些消息被接收方接收之前,对它们进行一系列的 处理、转换

observer 的三个属性

  • 推荐把 Observable 用于:事件处理、异步编程、处理多个值
  • observer(观察者)是对象,包含三个属性:next,error,complete
  1. 【必须】next:以接收的值作为入参,正常时执行
  2. 【可选】error:出错时执行
  3. 【可选】complete:传输完成时执行

创建可观察对象(法一:of()、from())

  • of(...items):返回 Observable 实例,用 同步方式,把 参数中的值 发送出来
  • from(iterable) :返回 Observable 实例,用于把 参数中的数组 转换成一个(发送 多个值 的)可观察对象

实例练习:创建并订阅一个可观察对象,让它的观察者把接收的消息,记录到控制台中

  1. 通过 of()、form() 接受值或者数组,创建可观察对象
  2. 创建 可观察对象的参数 观察者,并定义观察者的 next()、error()、complete() 方法
  3. 将 观察者 放入 可观察对象 中,并进行订阅
  • 简化上面三步:创建可观察对象,将观察者的方法直接写入订阅方法中
// 创建可观察对象(通过 of()):
const myObservable = of(1, 2, 3);
// 观察者:
const myObserver = {
  next: x => console.log('Observer got a next value: ' + x),
  error: err => console.error('Observer got an error: ' + err),
  complete: () => console.log('Observer got a complete notification'),
};
// 可观察对象被订阅:
myObservable.subscribe(myObserver);
——————————————————————————————————————————————————————————————————————————
// 简写 可观察对象被订阅:
myObservable.subscribe(
  x => console.log('Observer got a next value: ' + x),
  err => console.error('Observer got an error: ' + err),
  () => console.log('Observer got a complete notification')
);
——————————————————————————————————————————————————————————————————————————
// Logs:
// Observer got a next value: 1
// Observer got a next value: 2
// Observer got a next value: 3
// Observer got a complete notification

 

 创建可观察对象(法二:订阅者函数 sequenceSubscriber)

  1. 通过 订阅者函数 sequenceSubscriber() 接收观察者,并在其中定义 next()、error()、complete() 方法
  2. 显示创建可观察对象,并传入 订阅者函数 new Observable(sequenceSubscriber),最后存储在一个变量里
  3. 将上述变量进行订阅,订阅方法内再次调用 next()、error()、complete() 方法
// 订阅者函数:生产者向消费者推送消息的地方
function sequenceSubscriber(observer) {
  observer.next(1);
  observer.next(2);
  observer.next(3);
  observer.complete();
  return {unsubscribe() {}};
}
// 创建 Observable 对象时,需要传入订阅者函数(subscriber)作为构造函数的参数
const sequence = new Observable(sequenceSubscriber);
// Observable 对象被订阅
sequence.subscribe({
  next(num) { console.log(num); },
  complete() { console.log('Finished sequence'); }
});

// Logs:
// 1
// 2
// 3
// Finished sequence
  • 加强上述过程,用 内联方法 定义 订阅者函数 (这没看懂)
function fromEvent(target, eventName) {
  return new Observable((observer) => {
    const handler = (e) => observer.next(e);

    // Add the event handler to the target
    target.addEventListener(eventName, handler);

    return () => {
      // Detach the event handler from the target
      target.removeEventListener(eventName, handler);
    };
  });
}

// 用这个函数来创建可发布 keydown 事件的可观察对象:
const ESC_KEY = 27;
const nameInput = document.getElementById('name') as HTMLInputElement;

const subscription = fromEvent(nameInput, 'keydown')
  .subscribe((e: KeyboardEvent) => {
    if (e.keyCode === ESC_KEY) {
      nameInput.value = '';
    }
  });

Observable 捕获错误

  • 由于可观察对象会 异步 生成值,无法用 try / catch 捕获错误
  • 在观察者中指定 error() 回调处理错误
myObservable.subscribe({
  next(num) { console.log('Next num: ' + num)},
  error(err) { console.log('Received an errror: ' + err)}
});
 

可观察对象 是 Angular 中处理 异步操作 的接口

  • 可观察对象 是 Angular 中处理 异步操作 的接口,作用如下:
  1. EventEmitter 类派生自 Observable
  2. HTTP 模块使用  Observable 来处理 AJAX 请求和响应
  3. 路由器、表单模块使用  Observable 监听对用户输入事件的响应

在组件之间传递数据

  1. EventEmitter 类,通过组件的 @Output() 装饰器 发送一些值
  2. EventEmitter 类,添加了 emit() 方法,这样它就可以发送任意值了
  3. 调用 emit(),就会把所发送的值传给观察者的 next() 方法
  • 下面这个范例组件监听了 open 和 close 事件:<zippy (open)="onOpen($event)" (close)="onClose($event)"></zippy>
<zippy (open)="onOpen($event)" (close)="onClose($event)"></zippy>
// 组件的定义如下:
@Component({
  selector: 'zippy',
  template: `
  <div class="zippy">
    <div (click)="toggle()">Toggle</div>
    <div [hidden]="!visible"> 我是内容 </div>
  </div>`})

export class ZippyComponent {
  // 当前状态可见
  visible = true; 
  // EventEmitter 类,通过组件的 @Output() 装饰器 发送一些值
  @Output() open = new EventEmitter<any>();
  @Output() close = new EventEmitter<any>();

  toggle() {
    // 获取当前状态并进行取反
    this.visible = !this.visible;
    if (this.visible) {
      this.open.emit(null);
    } else {
      this.close.emit(null);
    }}}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

基于可观察对象(Observable)的 HTTP API

  • Angular 的 HttpClient 从 HTTP 方法调用中,返回了可观察对象 Observable
  • 例如:http.get(‘/api’) 就会返回可观察对象 Observable
  • 相对于基于承诺(Promise)的 HTTP API,基于可观察对象(Observable)的 HTTP API 有一系列 优点:
  1. 可观察对象不会修改服务器的响应(和在承诺上串联起来的 .then() 调用一样),但可以使用一系列 操作符 按需转换 这些响应
  2. 可观察对象的 HTTP 请求可以通过 unsubscribe() 【翻译:取消订阅】方法取消
  3. 请求可以进行配置,可以获取进度事件的变化
  4. 失败的请求很容易重试

Async 管道

  • AsyncPipe 会订阅 可观察对象 承诺,并 返回 其发出的 最后一个值
  • 当发出新值时,Async 管道就会把该组件标记为 需要进行变更检查的(故可能导致刷新)
  • 下面的例子把 time 这个可观察对象绑定到了组件的视图中。它会不断使用 当前时间 更新组件的视图

@Component({
  selector: 'async-observable-pipe',
  template: `<div><code>observable|async</code>:

       // 下面就是 Async 管道
       Time: {{ time | async }}</div>` 
})
export class AsyncObservablePipeComponent {
  time = new Observable<string>(observer => {
    setInterval(() => observer.next(new Date().toString()), 1000);

  });
}

  • Observable:可观察对象
  • observer:观察者
  • observer.next():观察者下一步操作

路由器 (router)【存在问题】

  • Router.events 以 Observable 的形式提供了其事件,可以使用 RxJS 中的 filter()操作符 来找到并订阅事件
  • NavigationStart:
import { Router, NavigationStart } from '@angular/router';
import { filter } from 'rxjs/operators';

export class Routable1Component implements OnInit {
  navStart: Observable<NavigationStart>;
  constructor(private router: Router) {
    this.navStart = router.events.pipe(
      // 过滤得到指定类型的事件
      filter(evt => evt instanceof NavigationStart)
    ) as Observable<NavigationStart>;
  }

  ngOnInit() {
    // 进行订阅
    this.navStart.subscribe(evt => console.log('Navigation Started!'));
  }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
  • ActivatedRoute:
import { ActivatedRoute } from '@angular/router';

export class Routable2Component implements OnInit {
  constructor(private activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    // 进行订阅
    this.activatedRoute.url
      .subscribe(url => console.log('即将跳转的路由地址是: ' + url));
  }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

响应式表单 (reactive forms)

  • FormControl valueChanges 属性statusChanges 属性 包含了 会发出 变更事件 的可观察对象
import { FormGroup } from '@angular/forms';

export class MyComponent implements OnInit {
  // 名字更改日志
  nameChangeLog: string[] = [];
  // 响应式表单
  heroForm: FormGroup;

  ngOnInit() {
    this.logNameChange();
  }

  logNameChange() {
    // 获取名字响应式表单
    const nameControl = this.heroForm.get('name');
    // 名字响应式表单的 valueChanges属性 包含变更事件
    nameControl.valueChanges.forEach(
      (value: string) => this.nameChangeLog.push(value)
    );}
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

Observables VS promises

  1. 可观察对象在被订阅之前,不会执行;承诺是在创建时立即执行
  2. 可观察对象能获取多个值,承诺只获取一个
  3. 可观察对象会区分 串联处理 和 订阅语句,承诺只有 .then() 语句
  4. 可观察对象的 subscribe() 会处理错误,承诺会把错误推送给子承诺
 创建转换订阅取消订阅
Observables

new Observable((observer) => {
  observer.next(123);
});

obs.pipe(map((value) => value * 2));sub = obs.subscribe((value) => {
  console.log(value)
});
sub.unsubscribe();
promisesnew Promise((resolve, reject) => {
  resolve(123);
});
promise.then((value) => value * 2);promise.then((value) => {
  console.log(value);
});
承诺被解析时隐式完成

Observables VS  Events API

 创建与取消订阅配置
Observables

// 创建可观察对象订阅

let clicks$ = fromEvent(buttonEl, ‘click’);
let subscription = clicks$.subscribe(e => console.log(‘Clicked’, e)) 

// 取消订阅
subscription.unsubscribe();

observable.subscribe(() => { });// 监听按键,提供一个流来表示这些输入的值
fromEvent(inputEl, 'keydown').pipe( 
  map(e => e.target.value)
);
Events API

// 建立并开始监听事件

button.addEventListener(‘click’, handler);

// 取消监听
button.removeEventListener(‘click’, handler);

function handler(e) {
  console.log(‘Clicked’, e);
}

element.addEventListener(eventName, (event) => { });

// 不支持配置

element.addEventListener(eventName, (event) => { });

Observables VS  Array

  1. 可观察对象会 随时间生成值,数组是 静态创建值
  2. 可观察对象是 异步 的,数组是 同步 的
  • 假设符号 ➞ 表示异步传值:
 给出值concat()filter():全部找到才停止find():找到一个就停止findIndex()【这没太看懂】遍历:tap()、forEach()map()reduce()【这没太看懂】
Observablesobs: ➞1➞2➞3➞5➞7
obsB: ➞'a'➞'b'➞'c'
concat(obs, obsB)
➞1➞2➞3➞5➞7➞'a'➞'b'➞'c'
obs.pipe(filter((v) => v>3))
➞5➞7
obs.pipe(find((v) => v>3))
➞5
obs.pipe(findIndex((v) => v>3))
➞3
obs.pipe(tap((v) => {
  console.log(v);
}))
1, 2, 3, 5, 7
obs.pipe(map((v) => -v))
➞-1➞-2➞-3➞-5➞-7
obs.pipe(reduce((s,v)=> s+v, 0))
➞18
Arrayarr: [1, 2, 3, 5, 7]
arrB: ['a', 'b', 'c']
arr.concat(arrB)
[1,2,3,5,7,'a','b','c']
arr.filter((v) => v>3)
[5, 7]
arr.find((v) => v>3)
5
arr.findIndex((v) => v>3)
3
arr.forEach((v) => {
  console.log(v);
})
1, 2, 3, 5, 7
arr.map((v) => -v)
[-1, -2, -3, -5, -7]
arr.reduce((s,v) => s+v, 0)
18

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lyrelion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值