Angular进阶之十:toPromise废弃原因及解决方案

背景

Rxjs从V7开始废弃了toPromise, V8中会删除它。

原因

1:toPromise()只返回一个值

toPromise()将 Observable 序列转换为符合 ES2015 标准的 Promise 。它使用 Observable 序列的最后一个值。

例:

import { Observable } from "rxjs";
……
myObservable = new Observable<string>((observer) => {
    observer.next('Hello');
    observer.next('World');
    observer.complete();
});

获取并打印结果,toPromise()后只获取了最后一个结果'World'

this.myObservable.toPromise().then((value: string) => {
      console.log(`toPromise: ${value}`);
});

2:Observable 可能不产生值或产生多个值

Observable 和 Promise 之间的相似之处在于,两者都可能随着时间的推移产生值,但不同之处在于,Observable 可能不产生值或产生多个值,而 Promise在成功解析时仅产生一个值。

例:增加代码如下

this.myObservable.subscribe((value: string) => {
      console.log(`observable: ${value}`);
});

Observable产生两个值

如果我们注释掉下面代码,Observable不产生值但Promise产生一个undefined值,

myObservable = new Observable<string>((observer) => {
    // observer.next('Hello');
    // observer.next('World');
    observer.complete();
});

因此,在V7 中,Observable 的 toPromise() 方法的返回类型已修复,以更好地反映 Observable 可以产生零值的事实。对于某些项目来说,这可能是一个重大变化,因为返回类型已从 Promise<T> 更改为 Promise<T | undefined>。

3:toPromise() 方法名不明确

toPromise() 方法名称从未指示 Promise 将解析为发出的哪个值,因为 Observable 可以随时间产生多个值。转换为 Promise 时,您可能希望选择要选择哪个值 - 第一个到达的值或最后一个值。为了解决所有这些问题,rxjs决定弃用 toPromise(),

解决方案

作为已弃用的 toPromise() 方法的替代,您应该使用两个内置静态转换函数 firstValueFrom 或 lastValueFrom。

1:lastValueFrom

lastValueFrom 几乎与 toPromise() 完全相同,这意味着它将在 Observable 完成时解析为到达的最后一个值。

例:增加代码

const lastValue = await lastValueFrom(this.myObservable);
console.log(`lastValueFrom: ${lastValue}`);

但当 Observable 完成而未发出值时,行为有所不同。当 Observable 完成而未发出时,toPromise() 将成功解析为 undefined(因此返回类型会发生变化),而 lastValueFrom 将拒绝并返回 EmptyError。因此,lastValueFrom 的返回类型是 Promise<T>,就像 RxJS 6 中的 toPromise() 一样。

例:

myObservable = new Observable<string>((observer) => {
    // observer.next('Hello');
    // observer.next('World');
    observer.complete();
});
this.myObservable.toPromise().then((value: string | undefined) => {
      console.log(`toPromise: ${value}`);
});
const lastValue = await lastValueFrom(this.myObservable);
console.log(`lastValueFrom: ${lastValue}`);

2:firstValueFrom

但是,您可能希望在第一个值到达时立即获取它,而不等待 Observable 完成,因此您可以使用 firstValueFrom。firstValueFrom 将使用 Observable 发出的第一个值解析 Promise,并立即取消订阅以保留资源。

例:增加代码

const firstValue = await firstValueFrom(this.myObservable);
console.log(`firstValueFrom: ${ firstValue}`);

如果 Observable 完成且未发出任何值,firstValueFrom 也会拒绝并出现 EmptyError。

例:

myObservable = new Observable<string>((observer) => {
    // observer.next('Hello');
    // observer.next('World');
    observer.complete();
});
this.myObservable.toPromise().then((value: string | undefined) => {
      console.log(`toPromise: ${value}`);
});
const firstValue = await firstValueFrom(this.myObservable);
console.log(`firstValueFrom: ${ firstValue}`);

默认值

无论是哪种替代方案,我们都可以设置默认值,以防止EmptyError发生。

例:

const firstValue = await firstValueFrom(this.myObservable, { defaultValue: "''" });
console.log(`firstValueFrom: ${ firstValue}`);
const lastValue = await lastValueFrom(this.myObservable, { defaultValue: "''" });
console.log(`lastValueFrom: ${lastValue}`);

最后

仅当您知道 Observable 最终会完成时才使用 lastValueFrom 函数。如果您知道 Observable 将发出至少一个值或最终会完成,则应使用 firstValueFrom 函数。

如果源 Observable 未完成或未发出,您最终会得到一个挂起的 Promise,并且异步函数的所有状态都可能挂在内存中。

为了避免这种情况,请考虑添加 timeouttaketakeWhiletakeUntil 等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值