rxjs 6中被废弃的toPromise(译)

2,856 阅读4分钟

大家好,在升级rxjs从6至7后,发现了ObservabletoPromise方法被废弃了,觉得很有意思,所以记录下来,望指正。

翻译自rxjs官网Conversion to Promises

Conversion to Promises 转换为Promise

The similarity between Observables and Promises is that both collections may produce values over time, but the difference is that Observables may produce none or more than one value, while Promises produce only one value when resolved successfully.

Observable和Promise的相似点是两者都可以随着时间推移产生值,但是区别是,Observable可以不产生值或者多个值,但是当Promise resolve成功的时候只生产一个值。

Issues 问题

For this reason, in RxJS 7, the return type of the Observable's toPromise() method has been fixed to better reflect the fact that Observables can yield zero values. This may be a breaking change to some projects as the return type was changed from Promise<T> to Promise<T | undefined>.

由于这个原因,在RxJS 7中,Observable的toPromise函数返回的类型已经被修复,可以更好的反映出Observable可以生产零个值(不生产值)。这可能对于一些项目来说是很大的改动,因为返回的类型是从Promise<T>变成了Promise<T | undefined>

Also, toPromise() method name was never indicating what emitted value a Promise will resolve with because Observables can produce multiple values over time. When converting to a Promise, you might want to choose which value to pick - either the first value that has arrived or the last one. To fix all these issues, we decided to deprecate toPromise(), and to introduce the two new helper functions for conversion to Promises.

另外,因为Observable能随着时间产生多个值,从toPromise()方法中从来不会显性看出转换后的Promise会resolve什么样的值。所以当将Observable转换为Promise时,你可能想要选择第一个或者最后一个产生的值转换为Promise。为了解决这些问题,我们决定废弃toPromise(),并且介绍两个新的helper方法用于转换Observable为Promise。

Use one of the two new functions 使用两个新方法之一

As a replacement to the deprecated toPromise() method, you should use one of the two built in static conversion functions firstValueFrom or lastValueFrom.

firstValueFrom 或者 lastValueFrom 静态方法应该替代被废弃的 toPromise()方法用于转换成Promise。

lastValueFrom

The lastValueFrom is almost exactly the same as toPromise() meaning that it will resolve with the last value that has arrived when the Observable completes, but with the difference in behavior when Observable completes without emitting a single value. When Observable completes without emitting, toPromise() will successfully resolve with undefined (thus the return type change), while the lastValueFrom will reject with the EmptyError. Thus, the return type of the lastValueFrom is Promise<T>, just like toPromise() had in RxJS 6.

lastValueFrom几乎与toPromise() 一个意思,在Observable complete的时候,lastValueFrom会带着Observable最后一个产生的值resolve,但是不同之处在于Observable不带值complete的情况下。 当Observable不产生值并且complete时,toPromise方法会成功resolve为undefined(也就是返回类型改变了,不再是T),但是lastValueFrom会带着EmptyErrorreject。因此,就如同在RxJS 6里一样,它的返回类型是Promise<T>

Example 举例

import { interval, lastValueFrom } from 'rxjs';
import { take } from 'rxjs/operators'async function execute() {  
    const source$ = interval(2000).pipe(take(10));  
    const finalNumber = await lastValueFrom(source$);  
    console.log(`The final number is ${finalNumber}`);
} 
execute(); // Expected output:// "The final number is 9"

firstValueFrom

However, you might want to take the first value as it arrives without waiting an Observable to complete, thus you can use firstValueFrom. The firstValueFrom will resolve a Promise with the first value that was emitted from the Observable and will immediately unsubscribe to retain resources. The firstValueFrom will also reject with an EmptyError if the Observable completes with no values emitted.

然而,你可能不等Observable complete,想要使用其第一个生产的值,因此可以用firstValueFromfirstValueFrom会将Observable第一个生产的值resolve并且立刻unsubscribe保存该值。firstValueFrom也会在Observable没有值产生而complete的情况下带着 EmptyErrorreject。

Example

import { interval, firstValueFrom } from 'rxjs'async function execute() {  
    const source$ = interval(2000);  
    const firstNumber = await firstValueFrom(source$);  
    console.log(`The first number is ${firstNumber}`);
} 
execute(); // Expected output:// "The first number is 0"

Both functions will return a Promise that rejects if the source Observable errors. The Promise will reject with the same error that the Observable has errored with.

若Observable源报错,两种方法都会返回Promise reject的状态。Promise也会带着Observable同样的错误reject。

Use default value EmptyErrorreject情况下设置默认resolve的值

If you don't want Promises created by lastValueFrom or firstValueFrom to reject with EmptyError if there were no emissions before completion, you can use the second parameter. The second parameter is expected to be an object with defaultValue parameter. The value in the defaultValue will be used to resolve a Promise when source Observable completes without emitted values.

当Observable complete之前没有产生值,如果你不想使用lastValueFrom或者firstValueFrom生成的Promise带着EmptyError reject,你可以用一个defaultValue的对象作为参数。在Observable没有产生值并且complete的情况下,这个defaultValue将会被resolve。

import { firstValueFrom, EMPTY } from 'rxjs';

const result = await firstValueFrom(EMPTY, { defaultValue: 0 });
console.log(result);

// Expected output:
// 0

Warning 注意

Only use lastValueFrom function if you know an Observable will eventually complete. The firstValueFrom function should be used if you know an Observable will emit at least one value or will eventually complete. If the source Observable does not complete or emit, you will end up with a Promise that is hung up, and potentially all of the state of an async function hanging out in memory. To avoid this situation, look into adding something like timeouttaketakeWhile, or takeUntil amongst others.

当你知道一个Observable最终会complete的情况下,只使用 lastValueFrom 方法。 当你知道一个Observable会生产至少一个或者最终complete的情况下, firstValueFrom应该被使用。当Observable源不会complete或者生产值,你将会面临Promise被挂起的情况,有可能所有async方法状态在内存中挂起。为了避免这个情况,检查是否可以添加其他操作符,例如 timeouttaketakeWhiletakeUntil等。