カテゴリー
【Angular活用講座】Rxjs:repeatオペレーターで一定時間間隔の処理(再帰的ループ)を行わせてみる
※ 当ページには【広告/PR】を含む場合があります。
2022/05/11
2022/10/06
2つのタイマー 〜 setIntervalと再帰setTimeoutの違いを知る
let timerId = setTimeout(function tick() {
//...定期実行したい処理を記述
timerId = setTimeout(tick, 1000);
}, 1000);
repeatオペレーターで作るRxjs版の再帰ループ処理
rxjs/operators
rxjs
再帰ループ処理の基本形
import { defer, repeat, share, Subject, takeUntil } from 'rxjs';
//...中略
@Injectable({
providedIn: 'any'
})
export class HogeTimerService {
private stopPolling = new Subject();
const source = defer(() => http.get('https://hoge.com/api'));
private myInterval$ = source.pipe(
repeat({ delay: 5000 }),
share(),
takeUntil(this.stopPolling)
);
//...略
takeUntil
share
retry
import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, defer,repeat, share, Subject, takeUntil } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class HogeService implements OnDestroy {
private myInterval$: Observable<any>;
private stopNotifier = new Subject();
constructor(private http: HttpClient) {
this.myInterval$ = defer(() => http.get('https://hoge.com/api')).pipe(
repeat({ delay: 5000 }),
share(),
takeUntil(this.stopNotifier)
);
}
hogeInfo(): Observable<any> {
return this.myInterval$;
}
ngOnDestroy() {
this.stopNotifier.next(null);
}
}
defer
repeat
repeatオペレーターの処理をもっとよく理解する
let myInterval$: Observable<any>;
let stopNotifier = new Subject();
//👇待機するだけのsleepメソッド
const sleep = async (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
//👇指定時間だけ遅れて実行されるだけのObservableを返す関数
function deferFromAsync$(ms: number) : Observable<any> {
return defer(async () => {
//👇指定時間(ミリ秒)だけ待機
await sleep(ms);
return ms;
});
}
const baseTime = Date.now();
let counter = 0;
//👇内部処理時間として500ms待機
myInterval$ = deferFromAsync$(500).pipe(
tap((res: number) => {
console.log(`[ループ#${++counter}]遅延時間:${~~res}[ms] -> 積算経過時間:${Date.now() - baseTime}[ms]`);
}),
repeat({ delay: 1000 }),
takeUntil(stopNotifier)
);
console.log(`ループ処理タイマーを開始します`);
myInterval$.subscribe();
//👇10秒後にタイマー終了する
setTimeout(() => {
console.log(`10秒経過したのでタイマーを終了します`);
stopNotifier.next(null);
}, 10000);
ループ処理タイマーを開始します
[ループ#1]遅延時間:500[ms] -> 積算経過時間:507[ms]
[ループ#2]遅延時間:500[ms] -> 積算経過時間:2011[ms]
[ループ#3]遅延時間:500[ms] -> 積算経過時間:3513[ms]
[ループ#4]遅延時間:500[ms] -> 積算経過時間:5015[ms]
[ループ#5]遅延時間:500[ms] -> 積算経過時間:6517[ms]
[ループ#6]遅延時間:500[ms] -> 積算経過時間:8019[ms]
[ループ#7]遅延時間:500[ms] -> 積算経過時間:9521[ms]
10秒経過したのでタイマーを終了します
takeUntil
repeat
//...
myInterval$ = deferFromAsync$(500).pipe(
//👈repeat(...)はココでも良い
tap(...),
//👈repeat(...)はココでも良い
tap(...),
//👈repeat(...)はココでも良い
tap(...),
repeat({ delay: 1000 }),
tap(...),
//👈repeat(...)はココでも良い
takeUntil(stopNotifier)
);
//...
takeUntil
//...
myInterval$ = deferFromAsync$(500).pipe(
tap(...),
tap(...),
tap(...),
takeUntil(stopNotifier),
repeat({ delay: 1000 }), //✖repeat(...)は機能しない
);
//...
repeat
repeat
loop.ts
//...中略
myInterval$ = deferFromAsync$(500).pipe(
tap((res: number) => {
console.log(`[ループ#${++counter}]遅延時間:${~~res}[ms] -> 積算経過時間:${Date.now() - baseTime}[ms]`);
}),
repeat({ delay: 1000 }),
tap((res: number) => {
console.log(`[ループ#${++counter}]repeatの後ろはdelayしない -> 積算経過時間:${Date.now() - baseTime}[ms]`);
}),
takeUntil(stopNotifier)
);
//...以下略
ループ処理タイマーを開始します
[ループ#1]遅延時間:500[ms] -> 積算経過時間:507[ms]
[ループ#1]repeatの後ろはdelayしない -> 積算経過時間:507[ms]
[ループ#2]遅延時間:500[ms] -> 積算経過時間:2010[ms]
[ループ#2]repeatの後ろはdelayしない -> 積算経過時間:2011[ms]
[ループ#3]遅延時間:500[ms] -> 積算経過時間:3513[ms]
[ループ#3]repeatの後ろはdelayしない -> 積算経過時間:3513[ms]
[ループ#4]遅延時間:500[ms] -> 積算経過時間:5015[ms]
[ループ#4]repeatの後ろはdelayしない -> 積算経過時間:5015[ms]
[ループ#5]遅延時間:500[ms] -> 積算経過時間:6517[ms]
[ループ#5]repeatの後ろはdelayしない -> 積算経過時間:6517[ms]
[ループ#6]遅延時間:500[ms] -> 積算経過時間:8019[ms]
[ループ#6]repeatの後ろはdelayしない -> 積算経過時間:8020[ms]
[ループ#7]遅延時間:500[ms] -> 積算経過時間:9521[ms]
[ループ#7]repeatの後ろはdelayしない -> 積算経過時間:9521[ms]
10秒経過したのでタイマーを終了します
//...中略
myInterval$ = deferFromAsync$(500).pipe(
tap((res: number) => {
console.log(`[ループ#${++counter}]遅延時間:${~~res}[ms] -> 積算経過時間:${Date.now() - baseTime}[ms]`);
}),
delay(1000),
tap((res: number) => {
console.log(`[ループ#${counter}]1000msのdelayあり -> 積算経過時間:${Date.now() - baseTime}[ms]`);
}),
repeat(),
takeUntil(stopNotifier)
);
//...以下略
ループ処理タイマーを開始します
[ループ#1]遅延時間:500[ms] -> 積算経過時間:505[ms]
[ループ#1]1000msのdelayあり -> 積算経過時間:1507[ms]
[ループ#2]遅延時間:500[ms] -> 積算経過時間:2009[ms]
[ループ#2]1000msのdelayあり -> 積算経過時間:3010[ms]
[ループ#3]遅延時間:500[ms] -> 積算経過時間:3511[ms]
[ループ#3]1000msのdelayあり -> 積算経過時間:4513[ms]
[ループ#4]遅延時間:500[ms] -> 積算経過時間:5014[ms]
[ループ#4]1000msのdelayあり -> 積算経過時間:6015[ms]
[ループ#5]遅延時間:500[ms] -> 積算経過時間:6516[ms]
[ループ#5]1000msのdelayあり -> 積算経過時間:7516[ms]
[ループ#6]遅延時間:500[ms] -> 積算経過時間:8017[ms]
[ループ#6]1000msのdelayあり -> 積算経過時間:9026[ms]
[ループ#7]遅延時間:500[ms] -> 積算経過時間:9527[ms]
10秒経過したのでタイマーを終了します
delay
repeat
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー