Angular---rxjs

Rxjs

简介

RxJS是一个主要用于处理异步程序的函数式编程库,可以把 RxJS 想成处理 异步行为 的 Lodash。

常见的异步行为

ajax,定时器,事件

常见的 优化异步回调的方式

Promise,async/await,rxjs

函数式编程

是一种编程思想的,就像面向过程、面向对象一样 比如:

const result = (5 + 6) - 2 * 3;

函数式的写法:

const add = (a, b) => a + b
const mul = (a, b) => a * b
const sub = (a, b) => a - b

const result = sub(add(5, 6), mul(2, 3))

把每个运算包成一个个不同的 function,并用这些 function 组合出我们要的结果,这就是最简单的 Functional Programming。

函数特性

  1. 一定会有返回值
  2. 不能产生副作用(纯函数)
  3. 纯函数的逻辑不能改变数据源
const arr = [1, 2, 3, 4, 5];
arr.slice(0, 3);
console.log(arr); // arr不变,slice就是个纯函数
arr.splice(0, 3, 2);
console.log(arr); // arr改变,splice是不纯的

rxjs vs Promise

官方文档

  1. 可观察对象是声明式的,在被订阅之前,它不会开始执行。promise是在创建时就立即执行的。这让可观察对象可用于定义那些应该按需执行的菜谱:
class AppComponent {
   
    newPromise() {
   
      const p = new Promise(resolve => {
   
        console.log('initial a promise'); // 创建后立即触发
      });
    }
    newObservable() {
   
      const o = new Observable(subscriber => {
   
        console.log('initial a newObservable'); // 没有订阅不触发
      });
    }
}
  1. 串联 跟第一条类似,只有当调用subscribe方法时,才会执行所有管道函数:
class AppComponent {
   
  // 串联起来会依次执行每个then中的打印日志
  newPromise() {
   
    const p = new Promise(resolve => {
   
      resolve(['a', 'b', 'c']);
    }).then(res => {
   
      console.log('第一个then');
      return res;
    }).then(res => {
   
      console.log('第2个then');
      return res;
    });
  }
  
  // 串联起来,但是没有订阅,不会执行
  newObservable() {
   
    const o = new Observable(subscriber => {
   
      console.log('initial a newObservable');
      subscriber.next(['a', 'b', 'c']);
    }).pipe(
      map(res => {
   
        console.log('第一个map');
        return res;
      }),
      map(res => {
   
        console.log('第2个map');
        return res;
      })
    );  // 不订阅,pipe中的所有函数都不会触发
  }
}
  1. Observable可以手动取消,而Promise被解析时自动完成:
// interval(1000) 每1s触发发送一条数据
const sub = interval(1000).subscribe(res => {
   
  console.log('interval', res);
});

// 可以手动取消订阅(可观察对象订阅为0时,就会停止执行)
class App {
   
  cancelObservable() {
   
      sub.unsubscribe();
  }
}
  1. 错误处理:
// 可观察对象的错误处理工作交给了订阅者的错误处理器,并且发生异常时该订阅者会自动取消对这个可观察对象的订阅
observable.subscribe(() => {
   
  throw new Error('my error');
});
// 承诺会把错误推给其子promise
promise.then(() => {
   
  throw new Error('my error');
});

Observable与Observer

Observable 可观察对象

Observable 可观察对象负责从数据源中推送数据:

import {
    Observable } from 'rxjs';

const observable = new Observable(subscriber => {
   
  // 推送三个数据
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
});

console.log('before subscribe');
observable.subscribe(x => {
   
  console.log('获得 value ' + x);
});
console.log('subscribe');

在这里插入图片描述

lazy computations

之前与Promise对比时讲过,只要不订阅(调用subscribe)Observable,Observable的回调函数就不会执行

import {
    Observable } from 'rxjs';

const foo = new Observable(subscriber => {
   
  console.log('Hello');
  subscriber.next(42);
});

foo.subscribe(x => {
   
  console.log(x);
});

Observable可同步,也可异步 推送值:

import {
    Observable } from 'rxjs';

const foo = new Observable(subscriber => {
   
  console.log('Hello');
  subscriber.next(42);
});

console.log('before');
foo.subscribe(x => {
   
  console.log(x);
});
console.log('after');

在这里插入图片描述
下面是异步:

import {
    Observable } from 'rxjs';

const foo = new Observable(subscriber => {
   
  console.log('Hello');
  subscriber.next(42);
  subscriber.next(100);
  subscriber.next(200);
  setTimeout(() => {
   
    subscriber.next(300); // happens asynchronously
  }, 1000);
});

console.log('before');
foo.subscribe(x => {
   
  console.log(x);
});
console.log('after');

在这里插入图片描述

创建Observables

可用new Observable() 创建,但实际情况更多的是用of, from, interval等操作符创建

import {
    Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
   
  const id = setInterval(() => {
   
    // 每秒推送一个 hi
    subscriber.next('hi')
  }, 1000);
});

Observer 观察者

Observer用户获取到Observable推送的值,Observers是一系列回调函数,也就是Observable.subscribe的回调函数

Observable.subscribe(x => console.log(x));

Observable.subscribe方法有三个回调函数,上面写的只是其中最常用的一个 next 回调函数

  • “Next”: 接收Observable推送过来但值
  • “Error”: 接收错误对象
  • “Complete”: 推送结束时触发(即使出现error),不会收到任何值
// 下面这种写法是按顺序定义subscribe的三个回调函数 next、error、complete ,顺序不能乱
observable.subscribe(value => {
   
  console.log('value', value);
}, error => {
   
  console.error('error err', error);
}, () => {
   
  console.log('complete');
});

// 完整写法,如果不需要error,可以删除error,只保留next和complete回调
observable.subscribe({
   
  next(value) {
   
    console.log('value', value);
  },
  error(error) {
   
    console.error('error', error);
  },
  complete() {
   
    console.log('complete');
  }
});

异常捕获

const observable = new Observable(function subscribe(subscriber) {
   
  subscriber.next(1);
  subscriber.next(2);
  subscriber.error(new Error('出错了'));
});

observable.subscribe(value => {
   
  console.log('value', value);
}, error => {
   
  console.error('error err', error);
}, () => {
   
  console.log('complete');
});

可以用try/catch捕获错误

import {
    Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
   
  try {
   
    subscriber.next(1);
    subscriber.next(2);
    subscriber.next(3);
    subscriber.complete();
  } catch (err) {
   
    subscriber.error(err); // delivers an error if it caught one
  }
});

手动结束推送

import {
    Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
   
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  // 不调用complete方法,下面的observable.subscribe就不会输出complete
  subscriber.complete();
  subscriber.next(4); // 结束后再推送值,observable.subscribe也接收不到了
});

observable.subscribe(value => {
   
  console.log('value', value);
}, error => {
   
  console.error('error', error);
}, () => {
   
  console.log('complete');
});

Subscription

observable.subscribe返回一个Subscription对象。可用于取消订阅,或添加/删除其他的子Subscription。

官方文档

const subscription = observable.subscribe(x => console.log(x));
调用subscription.unsubscribe()即可取消订阅

const observable = interval(1000);
const subscription = observable.subscribe(x => console.log(x));
setTimeout(() => {
   
  subscription.unsubscribe();
}, 5000);

什么是Operator

之前讲过什么是函数试编程,那么Operator就是一个个的函数,所以这些函数都具有函数式的特点:

  • 都有返回值
  • 不会对元数据产生副作用
    即每个操作符(函数),在拿到原Observable对象后,经过处理都是返回一个新的Observable。

比如下面这个自定义map函数:

// of操作符创建一个obervable对象,该 Observable 只发出给定的参数('Jerry', 'Anna')
const people = of('Jerry', 'Anna');

function map(source: Observable<string>, callback: (item: string) => string) {
   
  
  // map函数返回值是一个 可观察对象 observable
  return new Observable(observer => {
   
    // 订阅传入的 observable,并在next中调用回调函数处理数据流
    return source.subscribe(
      value => {
   
        try{
   
          observer.next(callback(value));
        } catch (e) {
   
          observer.error(e);
        }
      },
      (err) => {
    observer.error(err); },
      () => {
    observer.complete(); }
    );
  });
}

const helloPeople = map(people, (item) => item + ' Hello~');
// 订阅 helloPeople,拿到的res是已经调用回调函数处理过的数据流
helloPeople.subscribe(res => {
   
  console.log('res', res);
});

在这里插入图片描述

这个map函数符合函数式的特点,在rxjs中,可称它为一个操作符(operator)。
在这里插入图片描述

Operator分类

管道操作符:filter, take…
创建类操作符:of,from…

Marble diagrams

异步往往是复杂的,尤其是多个异步结合在一起的逻辑,用文字难以表达 所以出现了一种叫Marble diagrams的图形表示法,协助理解各種 operators! 参考:

30 天精通 RxJS (07)
rxmarbles

创建类操作符

参考官网 和 https://rxjs-cn.github.io/learn-rxjs-operators/

of

按顺序发出任意类型和数量的值

import {
    of } from 'rxjs';
const source = of(1, 2, 3, 4, 5);

// 输出: 1,2,3,4,5
source.subscribe(val => console.log(val));

// 复杂类型
const source = of({
    name: 'Brian' }, [1, 2, 3], function hello() {
   
  return 'Hello';
});

// 输出: {name: 'Brian}, [1,2,3], function hello() { return 'Hello' }
const subscribe = source.subscribe(val => console.log(val));
from

将数组、promise 或迭代器转换成 observable 转数组

import {
    from } from 'rxjs';
const arraySource = from([1, 2, 3, 4, 5]);

// 输出: 1,2,3,4,5
const subscribe = arraySource.subscribe(val => console.log(val));

转Promise:

import {
    from } from 'rxjs';

const promiseSource = from(new Promise(resolve => resolve('Hello World!')));

// 输出: 'Hello World'
const subscribe = promiseSource.subscribe(val => console.log(val));

转Map对象:

import {
    from } from 'rxjs';
const map = new Map([
  [1, 'hi']
]);
map.set(2, 'Bye');
map.set(3, 'rxjs');
const mapSource = from(map);

// 输出: [1, 'Hi'], [2, 'Bye'], [3, 'rxjs']
const subscribe = mapSource.subscribe(val => console.log(val));

转字符串:

import {
    from } from 'rxjs';

// 将字符串作为字符序列发出
const source = from('Hello World');

// 输出: 'H','e','l','l','o',' ','W','o','r','l','d'
source.subscribe(val => console.log(val));
empty

不带任何数据的的Observable, 会立即执行complete回调

import {
    empty } from 'rxjs';
const result = empty();
result.subscribe(res => console.log(res), error => {
   }, () => console.log('ok'));
fromEvent

将事件转换成 observable

import {
    fromEvent } from 'rxjs';
import {
    map } from 'rxjs/operators';

// 创建发出点击事件的 observable,document可以替换为任意dom,比如: button的click事件
const source = fromEvent(document, 'click');
const example = source.pipe(map(event => `Event time: ${
     event.timeStamp}`));
example.subscribe(val => console.log(val));
interval
import {
    interval } from 'rxjs';

// 每1秒发出数字序列中的值
const source = interval(1000);
// 数字: 0,1,2,3,4,5....
const subscribe = source.subscribe(val => console.log(val));
timer
import {
    timer } from 'rxjs';

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值