RxJS沉浸式入门教程

您所在的位置:网站首页 鳗鱼炖汤的做法的营养与功效 RxJS沉浸式入门教程

RxJS沉浸式入门教程

2023-11-10 01:08| 来源: 网络整理| 查看: 265

什么是RxJS【Reactive Extensions for JavaScript】

首先RxJS是一个库,是针对异步数据流编程工具,当然Angular引入RxJS就是让异步更加简单,更加可控,在开始RxJS之前,我们先来了解一下Reactive Programming,其本质就是使用流(stream)的一种编程方式。

什么是流呢?

首先看示例:

例子:有变量 a和b, b 永远等于 a + 1 // 基础写法 let a = 1; b = a + 1; console.log(b) a = 2; b = a + 1; // 每次a变化,都要执行一次b = a+ 1 console.log(b) // 使用流来解决: // 用 stream 描述 a 与 b 的关系。 const a$ = new Subject(); const b$ = a$.pipe(map( x=> x + 1)); b$.subscribe(console.log); a$.next(1); a$.next(2);

虽然在这里我们还不认识Subject是个什么,但是通过这个例子我们可以了解到,所谓流/stream,就是数据基于事件(event)变化的整体。stream = data + event,只要a变化,那么b就会自动跟着变化。

流的最大的好处是,能够监听数据的变化,执行相应的操作,从而最大可能性的减小性能的开销。对于rxjs而言任何东西都可以是streams

RxJS中的核心概念(Observable 、Observer 、Subscription、Subject)

在Angular项目中我们在调用接口的时候,常用的调用方式是:

this._exampleService.reportCurrentOpenTab$ .subscribe((res: number) => { this.currentIndex = res; }) //this._exampleService.reportCurrentOpenTab$ 这是返回observable,他可以是api的调用,可以是事件的调用等等

我们可以把上述的调用方式抽象一下为Observable.subscribe(observer),在这里我们认识到了两个新的事物分别是Observable和Observer,以及这个方法调用的返回对象,返回的是一个Subscription对象的实例化,接下来我们逐一介绍这些核心概念。

Observable

Observable是RxJS中最核心的一个概念,它的本质就是“Observable is a function to generate values”,首先它是一个函数,也就是说它是数据源头,是数据生产者,一般我们会在变量末尾加$表示Observable类型的对象。

// 此函数定义了setInterval 每两秒产生一个 value的功能 const observable$ = (observer) => { let counter = 0; const id = setInterval(() => observer.next(counter++), 2000); } // 因为Observable是个对象,所以需要调用才可以执行 observable$({ next: (val) => console.log(val) });

函数中会定义 value 的生成方式,函数调用时,observer.next 来执行在observer 中定义的行为,比如上述示例中的counter++。

必须调用(订阅)才会被执行observable 被调用后,必须能被关闭,否则会一只运行下去对于同一个 observable,在不同的地方 subscribe,是无关的。function 执行多次,互相没有关联是一致的 Observer

它是观察者,数据使用者,数据消费者。它是一个有三个回调函数的对象,每个回调函数对应三种Observable发送的通知类型(next, error, complete),observer表示的是对序列结果的处理方式。在实际开发中,如果我们提供了一个回调函数作为参数,subscribe会将我们提供的函数参数作为next的回调处理函数。next决定传递一个什么样的数据给观察者

let observer = { next: data => console.log('data'); // next表示数据正常流动, error: err=> console.log('err'); // error表示流中出错 complete: () => console.log('complete') // complete表示流结束 } // error和complete只会触发一个,但是可以有多个next Observables 与 Observer 之间的订阅发布关系(观察者模式) 如下:

订阅 :Observer 通过 Observable 提供的 subscribe() 方法订阅 Observable。 发布 :Observable 通过回调 Next 方法向 Observer 发布事件。

Subscription

observable.subscribe():是一个Subscription对象。在 observable.subscribe 内部,他会创建一个观察者对象并使用第一个回调函数作为next的处理方法。Subscription就是表示Observable 的执行,可以被清理。这个对象最常用的方法就是unsubscribe方法。同时,它还有add方法也可以使我们取消多个订阅,所以我们在Angular项目中会看到如下代码,去取消订阅:

// 定义Subscription类型的数组同于存放页面中的observable订阅过程中产生的Subscription public subscriptions: Subscription[] = []; public ngOnInit(): void { this.subscriptions.push( // 将Subscription push到定义的数组中去 this._layoutStatusService.reportCurOpenTab$ .subscribe((res: number) => { this.currentIndex = res; }) ); } // 在Angular的销毁生命周期中进行取消订阅,已达到优化性能的作用 public ngOnDestroy(): void { this.subscriptions.forEach((subscription) => subscription.unsubscribe()); }

我们可以用生活中 “订阅报刊” 的例子,再来理解一下订阅关系: 报刊生产商【observable】 市民【observer】

市民打电话给报刊生产商进行订阅【subscribe】,市民就会在报刊商送报纸(next)成功的时候收到报纸,这个时候市民是不用关心报纸是怎么生产和运送的,当然当报刊生产商可能会意外的导致送报纸失败(error),而等成功之后,报刊生产商还是会把这次送报标记为已送达(complete)

Subject

Subject是特殊的observable:我们可以像订阅任何observable一样去订阅subject。 Subject是观察者: 它有next(v),error(e),和complete()方法,如果我们需要给subject提供新值,只要调用next(v),它会将值多播给已注册监听该subject的观察者。 所以: Subject既是Observable,也是观察者(可以多个)

Subject与Observable的区别: Subject是多播的【他可以将值多播给多个观察者】普通的Observble是单播的【每个已经订阅的观察者(observer)都拥有observable的独立执行,上述Observble的介绍也有提及】 Subject中常用的子类(ReplaySubject、AsyncSubject、BehaviorSubject)

这里针对Subject的这三个衍生子类,只做简单的介绍,在后续开发过程中如果需要使用该方法,请自行查阅官网,进行进一步的深入了解。

BehaviorSubject: 会保存最先发送数据,当被订阅的时,会立即使用这个最新【最先的】数据,然后会继续接收新的next的值。BehaviorSubject必须设置默认值,因为他有一个最新值(当前值)的概念。ReplaySubject:会保存所有值,然后回放给最新的订阅者,当新的订阅发生的时候,会把上一次订阅的所有值都再次打印一遍~AsyncSubject:只有当Observable执行完成时complete(),它才会执行的最后一个值发送给观察者,就是说会保留流里最后一条数据,而且只会在数据流complete时候才会发送。 Subject的在Angular中的常见的作用:

可以在Angular通过service来实现不同组件,或者不同模块之间的传值

// 定义公共的用于数据存储的service,文件名是(eg:xampleStore.service.ts) @Injectable() export class ExampleStoreService { private currentTabNumber$ = new Subject(); } // 此数据更改的逻辑,可以在任何需要更改的地方进行next相对应的值,文件名是 (eg:a.component.ts) this.ExampleStoreService.currentTabNumber$.next(1); // 订阅接收到数据更改,并做下一步逻辑处理,文件名是(eg:b.component.ts) this.ExampleStoreService.currentTabNumber$ .subscribe((res: number) => { this.currentIndex = res; }) RxJS的操作符(Operator)简介

operators是个纯函数,它的输入为observable,返回也observable。operators的本质是,描述从一个数据流到另一个数据流之间的关系,也就是observer到observable中间发生的转换,很类似于Lodash。 在RxJS中操作符有接近100个,不过在开发过程稿常用的也就十多个。

常见的运算符包含 map,filter,concat,flatmap,switchmap,forkjoin 在这里我们只调挑出forkjoin来讲解一下,其他的操作符可以自己去查阅使用 forkjoin主要是用于多个接口都返回的时候,才会返回结果,有点类似于promise中的promise.all,具体的用法如下:

forkJoin([ this._aService.getData(), this._bService.getData() ]).subscribe(resArr => { // 此时的返回结果会被按顺序放在一个数组中 aData = resArr[0]; bData = resArr[1]; } Observable与Promise的比较: observable.subscribe(function next(value) {}); promise.then(function resolve(value) {});

从方法的调用上感觉这两种处理异步的形式是相似的,实际上observable比promise强大很多。具体对比如下:

Observable: RxJS 里面用的是 next() 和 subscribe()next 会被调用多次,可以发射多个值但是observable在没有 subscribe 的情况下,是不是被执行的。RxJS unsubscribe可以取消订阅RxJS还提供了大量的操作符,可以方便出来各种流的情况 Promise: Promise里面用的是 then() 和 resolve()resolve 只会被调用一次,不能多次触发异步调用,then并不会触发promise的执行。也就是说,一个 promise不管有没有then, 都会被执行。 Observable与Promise的转换

RxJS是有提供方法,用来进行observable与promise之间转换的,所以在其他使用promise的项目里完全可以使用RxJS去迭代开发。

const promise = observableFun$.toPromise() // 将observable转换成promise const observable = observable.fromPromise(promiseFun) // 将promise类型函数转换成observable 通过一个搜索示例,再来回顾一下今天介绍的RxJS

普通方式:

var inputControl = document.querySelector('#inputControl'), timer = null, currentSearchText = ''; text.addEventListener('keyup', (e) =>{ clearTimeout(timer) timer = setTimeout(() => { currentSearchText = ''; var searchText = e.target.value; $.ajax({ url: `/search/${searchText}`, success: data => { if (data.search === currentSearchText) { // 渲染展示 render(data); } else { // .. } } }); },300) })

使用流的方式:

var inputControl = document.querySelector('#inputControl'); var inputStream = fromEvent(inputControl, 'keyup') .pipe( .debounceTime(300) // 防抖动 .pluck('target', 'value') // 使用pluck操作符,获取输入的值 .switchMap(url => Http.get(url)) // 将当前输入流替换为http请求 .subscribe(data => render(data)); // 接收数据 总结

上述介绍的内容几乎都是Rxjs中很基础的东西,RxJS的入门确实有些难度,但是如果掌握了之后,你会发现RxJS这种响应式编程是真的香,本篇文章中并没有着重介绍RxJS中的操作符,如果想了解更多关于操作符可以参考RxJS的操作符介绍。

Rxjs官网:https://rxjs.dev/api



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3