angular promise请求_rxjs 实战之Promise
与promise转换Promise和rxjs在设计上是解决不同问题的工具,Promise解决的是js中异步回调的问题,rxjs则代表响应式编程,在更高层面提供异步数据流来帮助开发者开发应用。在功能上,rxjs可以通过Observable和operater组合完全达到Promise的效果,将这两者放在一起对比是不太公平的,本文就两者之间的转换联系,已经应用场景进行一些介绍。observable与Pr
与promise转换
Promise和rxjs在设计上是解决不同问题的工具,Promise解决的是js中异步回调的问题,rxjs则代表响应式编程,在更高层面提供异步数据流来帮助开发者开发应用。在功能上,rxjs可以通过Observable和operater组合完全达到Promise的效果,将这两者放在一起对比是不太公平的,本文就两者之间的转换联系,已经应用场景进行一些介绍。
observable与Promise之间的转换,必须提到observable的complete状态。所谓complete代表obesrvable的完成状态,在此状态之后,该obserable不会再接受后续的值。
import { Observable } from 'rxjs';
const observable = new Observable(function subscribe(subscriber) {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
subscriber.complete();
subscriber.next(4); // Is not delivered because it would violate the contract
});
结合angular的HttpClient服务get方法等请求得到的都是发射一个值紧接着一个complete通知的observable。源代码:
这样的observable直接就可以调用toPromise方法得到Promise并能正确resolve得到结果。如果是一个从不complete的Observable,则直接调用toPromise方法得到Promise永远都无法resolve。这原因本质上是两个工具的设计不同,如下代码解释。
const promise = new Promise(function (resolve, reject){
resolve('i am promise');
});
const observable = new Observable(function subscribe(subscriber) {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
subscriber.complete();
});
const observablePromise = obervable.toPromise();
observablePromise.then((value) => {
// value应该是1,2还是3?
// 如果按照调用`then`紧接着调用`subscribe`,那value应该是1,然后是2,然后是3. 但这与then的设计不符
console.log('observablePromise value', value);
});
如果要对一个未complete的Observable转换成promise,你需要指定在当前Observable流信息里摘取你需要有转化成promise的特定信息。
// first 取流中第一个数据,并发射complete信号
const firstPromise = observable.pipe(first());
// 取前三个数据,并进行归并
const threePromise = observable.pipe(
take(3),
reduce((acc, val) => acc + val, 0)
);
为什么要进行toPromise转换
其实从设计上看,Observable是比Promise强大非常多的工具,那是否在构建应用的时候使用Observale就可以了。这么说是没错,你完全可以通过只使用Observale来构建应该,比如Angular应用,可以完全不出现Promise。但Promise搭配async,await可以在很多情形下增加代码的可读性,维护成本,在一个方法体内,如果需要搭配多个Observable进行组合,使用toPromise搭配await,犹如看到一匹野马在奔跑一样顺畅。
以下代码可以在https://stackblitz.com/edit/rxjs-bmbnpm 进行调试
function pureObservable(conditionA: Observable<boolean>, conditionB: Observable<boolean>, executor: Observable<any>) {
return conditionA.pipe(
mergeMap((value) => {
if (value) {
return conditionB;
} else {
return of(value);
}
}),
mergeMap((value) => {
if (value) {
return executor;
} else {
return of(false);
}
}),
)
}
async function withPromise(conditionA: Observable<boolean>, conditionB: Observable<boolean>, executor: Observable<any>) {
const predicate = await conditionA.toPromise() && await conditionB.toPromise();
return predicate && await executor.toPromise();
}
为什么不只使用promise
**以下章节具有比较大的正义,为了Promise而Promise。实际上作者想要实现的是用observable实现能外部触发的promise。和设计,模式啥的都无关。评论者有对promise更本质的思考。
在开发非angular项目时,单纯使用promise搭配async,await存在最大的掣肘是原生ES规范的promise无法从外部调用resolve。例如如下代码,设计一个服务带有一个ready状态
class ServiceA {
// 状态异步
readyPromise = Promise.resolve(false);
data;
async fetchData() {
const ready = await this.readyPromise;
if (ready) {
return this.data;
} else {
const data = await this.http.get('/datas');
this.readyPromise = Promise.resolve(true);
this.data = data;
return data;
}
}
constructor(private http: HttpService) {
}
}
看上去这个服务非常健康,获取data的方法能够很好的工作
const sa = new ServiceA();
sa.fetchData().then(...);
但是如果外部获取这个服务的ready状态,则可能出现问题
// 以下异步直接resolve为false,无法监听到ready变为true的是件
const sa = new ServiceA();
sa.readyPromise.then(() => {
...
});
// 其他方法体内
sa.fetchData().then(...);
求助于stackoverflow最简单的实现方式是
readyResolve;
readyPromise = new Promise((resolve) => this.readyResolve = resolve)
// 你想要resolve地方
this.readyResolve(true)
通过rxjs
rxjs的Subject类可以从外部触发数据流,只需通过如下简单更改就可以实现ready状态。
class ServiceA {
private readySubject = new BehaviorSubject<boolean>(false);
readyPromise = this.readySubject.pipe(
filter((val) => val),
first(),
).toPromise();
data;
async fetchData() {
const ready = this.readySubject.getValue();
if (ready) {
return this.data;
} else {
const data = await this.http.get('/datas');
this.readyPromise.next(true);
this.data = data;
return data;
}
}
constructor(private http: HttpService) {
}
}
更多推荐
所有评论(0)