カテゴリー
【Rxjs基礎講座】deferでasync/await関数からObservableへ変換する
※ 当ページには【広告/PR】を含む場合があります。
2020/07/01
2022/10/05
defer
from
asycn/await
defer
TL;DR
// hoge()がasyncで実装された何かの関数
const obs$ = defer(async () => await hoge());
// obs$はObserbable<any>として、Promise内部で処理された
// awaitした変数を返す
obs$.subscribe(response => console.log(response));
// hoge(_arg)がasyncで実装された引数_arg付きの何かの関数
const obs$ = (_arg: any) => defer(async () => await hoge(_arg));
// 引数付きobs$はObserbable<any>として、Promise内部で処理された
// awaitした変数を返す
const hoge_arg = {name: 'hogehoge'};
obs$(hoge_arg).subscribe(response => console.log(response));
async関数をdeferを使ってObservableに書き換えるまでの出来るだけ略さない実装
import { Observable, defer } from 'rxjs';
function deferFromAsync$(): Observable<any> {
// 内部のasync関数
async function currentTime() {
return new Date();
};
async function futureDate() {
// async関数であるcurrentTime()の返り値が解決されるまで待機
const localdate = await currentTime();
return `The date after 100 years will be ${localdate.getFullYear() + 100}/${localdate.getMonth() + 1}/${localdate.getDate()}`;
}
// deferは更にasync関数であるfutureDate()の返り値が解決されるまで待機する
// ようなObservableを作成して返す
return defer(async function() {
return await futureDate();
});
//👆return defer(async () => await futureDate()); と同じ
}
const date = new Date();
console.log(`Now the date is ${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`);
deferFromAsync$().subscribe(res => console.log(res));
$ node dist/index.js
Now the date is 2020/7/1
The date after 100 years will be 2120/7/1
async/await
Promise型のオブジェクトを返す関数
async関数
function deferFromAsync$() : Observable<any> {
async function currentTime() {
return new Date();
};
async function futureDate() {
const localdate = await currentTime();
return `The date after 100 years will be ${localdate.getFullYear() + 100}/${localdate.getMonth() + 1}/${localdate.getDate()}`;
}
// 👇deferの引数にasync関数の参照を指定
return defer(futureDate);
}
async () => await futureDate()
futureDate
function deferFromAsync$() : Observable<any> {
async function currentTime() {
return new Date();
};
return defer(async () => {
const localdate = await currentTime();
return `The date after 100 years will be ${localdate.getFullYear() + 100}/${localdate.getMonth() + 1}/${localdate.getDate()}`;
});
}
rxjs
import { map } from 'rxjs/operators';
function deferFromAsync$() : Observable<any> {
async function currentTime() {
return new Date();
};
return defer(async () => await currentTime()).pipe(
map(localdate => `The date after 100 years will be ${localdate.getFullYear() + 100}/${localdate.getMonth() + 1}/${localdate.getDate()}`)
);
}
引数ありのasync関数をdefer変換する方法
defer
import { Observable, defer } from 'rxjs';
// 👇引数をもつasync関数
async function futureTime(localdate: any) {
return `The date after 100 years will be ${localdate.getFullYear() + 100}/${localdate.getMonth() + 1}/${localdate.getDate()}`;
};
function deferFromAsync$(arg: any) : Observable<any> {
// 👇引数argは外部async関数futureTimeに関数内で渡される
return defer(async function() {
return await futureTime(arg);
});
}
const date = new Date();
console.log(`Now the date is ${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`);
deferFromAsync$(date).subscribe(res => console.log(res));
()
deferFromAsync$
export const deferFromAsync$ = (arg: any) : Observable<any> => defer(async () => await futureTime(arg));
利用例① ~ switchMapを利用する
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
async function futureLocalTime(localdate: any) {
return `The date after 100 years will be ${localdate.getFullYear() + 100}/${localdate.getMonth() + 1}/${localdate.getDate()}`;
};
function switchMapFromPromise$(arg: any) : Observable<any> {
return of(arg).pipe(switchMap(arg_ => futureLocalTime(arg_)));
// 👇もしくは関数の参照を利用する場合でもOK
// return of(arg).pipe(switchMap(futureLocalTime));
}
const date = new Date();
console.log(`Now the date is ${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`);
switchMapFromPromise$(date).subscribe(res => console.log(res));
利用例② ~ puppeteerのページ遷移をrxjsで制御する
import { Observable, forkJoin, from, defer } from 'rxjs';
import { map, concatMap, delay } from 'rxjs/operators';
import puppeteer from 'puppeteer';
function multiNavigate$(page: puppeteer.Page, url: string): Observable<any> {
const nav$ = (url_: string) => defer(async () => await page.goto(url_));
const wait$ = from(page.waitForNavigation({timeout: 5000, waitUntil: "networkidle0"}));
const do_something$ = defer(async () => await page.$eval('[セレクタ]', e => e.innerHTML)).pipe(
map((res: string) => {
if (res) {
/// 現在のページにあるセレクタから次の遷移先のリンクを取得し、後段にそのurlを流す
return '取得したURLアドレス';
} else {
return '';
}
})
);
const capture$ = defer(() => page.screenshot({path: `./capture_page.png`}));
//👇①同期処理しながら指定先のリンク先のページへ3回遷移して画面をキャプチャさせる
return forkJoin([wait$, nav$(url)]).pipe(
delay(1000),
concatMap(_ => do_something$.pipe(
concatMap(url2 => forkJoin([wait$, nav$(url2)]).pipe(
delay(1000),
concatMap(_ => do_something$.pipe(
concatMap(url3 => forkJoin([wait$, nav$$(url3)]).pipe(
concatMap(_ => capture$)
))
))
))
)
),
);
}
(async () => {
const browser = await puppeteer.launch({
executablePath: '/usr/bin/chromium-browser',
args: ['--disable-dev-shm-usage', '--no-sandbox']
});
try {
const page: puppeteer.Page = await browser.newPage();
multiNavigate$(page, 'https://www.hoge.piyo.co.jp').subscribe();
} catch (e) {
throw e;
} finally {
await browser.close();
}
})();
nav$(URL)
ObservableからPromiseを行う逆変換 ~ toPromise
import { of } from 'rxjs';
function toPromise$() : Promise<any> {
return of(new Date()).toPromise();
}
toPromise$().then(res => console.log(res));
% node dist/index.js
2020-07-01T10:28:31.567Z
toPromise
fromではasync/awaitの変換はダメなのか
async/await
まとめ
async/await
defer
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー