【Angular】FirstValuefromの特徴
こんにちは。
フロントエンドエンジニアとしてAngularをメインにしているマサキです。
今回はFirstValuefromについて記事にしていきたいと思います。
FirstValuefromとは
FirstValuefromはRxJSのオペレーターです。
observableをサブスクライブして渡ってきた最初の値をObservableからPromiseに変換し、そのsubscriptionを自動的に終了させることが出来ます。
■ 構文
firstValueFrom<T, D>(source: Observable<T>, config?:FirstValueFromConfig<D>): Promise<T | D>
■ FirstValuefromの公式ドキュメント
これまでObservableからPromiseに変換する場合は、toPromiseを使用していましたが、ForstValueformはtoPromise×firstオペレーター×unsebscribeを一気に実行してくれるので、かなり便利なオペレーターかと思います。
また下記記事にもあるように、toPromiseは非推奨となりForstValueformを使用して下さいとのことなので、非同期処理を同期させる為に使用する機会が増えてくるのかと思います。
toPromiseが廃止の理由
toPromiseが廃止される理由は、Observable prototypeを統一するためとtoPromiseの場合、undefinedの挙動が不完全であり、使用する機会が限られてしまう為です。
import { EMPTY, of } from 'rxjs';
of(1, 2, 3, undefined).toPromise().then((value) => {
console.log(value) // undefined
});
EMPTY.toPromise().then((value) => {
console.log(value) // undefined
});
この場合、両方ともundefinedが返ってきます。
import { EMPTY, of } from 'rxjs';
of(1, 2, undefined, 3).toPromise().then((value) => {
console.log(value); // 3
});
EMPTY.toPromise().then((value) => {
console.log(value); // undefined
});
しかし、undefinedと3の順番を入れ替えた場合は3が返ってきます。値の順序によって最後の値をObservableからPromiseに変換するlastValueFromオペレータのような挙動になってしまいます。
FirstValuefromの挙動
FirstValuefromの特徴は先ほども述べた通り、最初の値(first value)を取得してObservableをPromiseに変換します。
import { interval, take, firstValueFrom } from 'rxjs';
async function execute() {
const source$ = interval(10).pipe(take(10));
const finalNumber = await firstValueFrom(source$);
console.log(`The final number is ${finalNumber}`);
// The final number is 0
}
execute();
最初の値である0をキャッチしてくれます。
ちなみに、lastValueFromオペレーターを使用した場合は、最後の値である9を取得することが出来ます。
import { interval, take, lastValueFrom } from 'rxjs';
async function execute() {
const source$ = interval(10).pipe(take(10));
const finalNumber = await lastValueFrom(source$);
console.log(`The final number is ${finalNumber}`);
// The final number is 9
}
execute();
EmptyError
値をキャッチする前にストリームが完了した場合、EmptyErrorが返ってきます。
If the observable stream completes before any values were emitted, the returned
promise will reject with EmptyError or will resolve with the default value if a default was specified.
import { interval, take, firstValueFrom } from 'rxjs';
async function execute() {
const source$ = interval(10).pipe(take(0));
const finalNumber = await firstValueFrom(source$)
.then((value) => {
console.log(`value:`, value);
})
.catch((error) => {
console.log(`error:`, error);
});
console.log(`The final number is ${finalNumber}`);
}
execute();
コンソールにEmptyErrorが表示され、値もundefinedが返ってきます。
error:
EmptyErrorImpl {
stack: "Error at _super
, name: "EmptyError",
message: "no elements in sequence"
}
The final number is undefined
catch、finally
Promiseに変換される為、catchやfinallyも使用することが出来ます。mapオペレーターでthrow new Errorを記載すると、エラーをcatchすることが出来ます。
import { interval, take, firstValueFrom, map } from 'rxjs';
async function execute() {
const source$ = interval(1000).pipe(
take(2),
map(() => {
throw new Error('error');
})
);
const finalNumber = await firstValueFrom(source$)
.then((value) => {
console.log(value);
})
.catch((error) => {
console.log(`Error:`, error); // Error: Error {}
})
.finally(() => {
console.log('finally'); // finally
});
console.log(`The final number is ${finalNumber}`);
}
execute();
記事はここまでとなります。
最後までお読み頂きありがとうございました。
Discussion