Learn RxJS
Search…
Http Polling

Examples

Example 1

This recipe demonstrates one way you can achieve polling an HTTP endpoint on an interval. This is a common task in web applications, and one that RxJS tends to handle really well as the continuous series of HTTP requests and responses is easy to reason about as a stream of data.
Could not load image
HTTP Polling
1
// Import stylesheets
2
import './style.css';
3
4
import { Observable, Subscription, of, fromEvent, from, empty, merge, timer } from 'rxjs';
5
import { map, mapTo, switchMap, tap, mergeMap, takeUntil, filter, finalize } from 'rxjs/operators';
6
7
declare type RequestCategory = 'cats' | 'meats';
8
9
// Constants for Cat Requests
10
const CATS_URL = "https://placekitten.com/g/{w}/{h}";
11
function mapCats(response): Observable<string> {
12
13
return from(new Promise((resolve, reject) => {
14
var blob = new Blob([response], {type: "image/png"});
15
let reader = new FileReader();
16
reader.onload = (data: any) => {
17
resolve(data.target.result);
18
};
19
reader.readAsDataURL(blob);
20
}));
21
}
22
23
// Constants for Meat Requests
24
const MEATS_URL = "https://baconipsum.com/api/?type=meat-and-filler";
25
function mapMeats(response): Observable<string> {
26
const parsedData = JSON.parse(response);
27
return of(parsedData ? parsedData[0] : '');
28
}
29
30
/*************************
31
* Our Operating State
32
*************************/
33
// Which type of data we are requesting
34
let requestCategory: RequestCategory = 'cats';
35
// Current Polling Subscription
36
let pollingSub: Subscription;
37
/*************************/
38
39
/**
40
* This function will make an AJAX request to the given Url, map the
41
* JSON parsed repsonse with the provided mapper function, and emit
42
* the result onto the returned observable.
43
*/
44
function requestData(url: string, mapFunc: (any) => Observable<string>): Observable<string> {
45
console.log(url)
46
const xhr = new XMLHttpRequest();
47
return from(new Promise<string>((resolve, reject) => {
48
49
// This is generating a random size for a placekitten image
50
// so that we get new cats each request.
51
const w = Math.round(Math.random() * 400);
52
const h = Math.round(Math.random() * 400);
53
const targetUrl = url
54
.replace('{w}', w.toString())
55
.replace('{h}', h.toString());
56
57
xhr.addEventListener("load", () => {
58
resolve(xhr.response);
59
});
60
xhr.open("GET", targetUrl);
61
if(requestCategory === 'cats') {
62
// Our cats urls return binary payloads
63
// so we need to respond as such.
64
xhr.responseType = "arraybuffer";
65
}
66
xhr.send();
67
}))
68
.pipe(
69
switchMap((data) => mapFunc(xhr.response)),
70
tap((data) => console.log('Request result: ', data))
71
);
72
}
73
74
75
/**
76
* This function will begin our polling for the given state, and
77
* on the provided interval (defaulting to 5 seconds)
78
*/
79
function startPolling(category: RequestCategory, interval: number = 5000): Observable<string> {
80
const url = category === 'cats' ? CATS_URL : MEATS_URL;
81
const mapper = category === 'cats' ? mapCats : mapMeats;
82
83
return timer(0, interval)
84
.pipe(
85
switchMap(_ => requestData(url, mapper))
86
);
87
}
88
89
// Gather our DOM Elements to wire up events
90
const startButton = document.getElementById('start');
91
const stopButton = document.getElementById('stop');
92
const text = document.getElementById('text');
93
const pollingStatus = document.getElementById('polling-status');
94
const catsRadio = document.getElementById('catsCheckbox');
95
const meatsRadio = document.getElementById('meatsCheckbox');
96
const catsClick$ = fromEvent(catsRadio, 'click').pipe(mapTo('cats'));
97
const meatsClick$ = fromEvent(meatsRadio, 'click').pipe(mapTo('meats'));
98
const catImage: HTMLImageElement = <HTMLImageElement>document.getElementById('cat');
99
// Stop polling
100
let stopPolling$ = fromEvent(stopButton, 'click');
101
102
function updateDom(result) {
103
if (requestCategory === 'cats') {
104
catImage.src = result;
105
console.log(catImage);
106
} else {
107
text.innerHTML = result;
108
}
109
}
110
111
function watchForData(category: RequestCategory) {
112
// Start new Poll
113
return startPolling(category, 5000).pipe(
114
tap(updateDom),
115
takeUntil(
116
// stop polling on either button click or change of categories
117
merge(
118
stopPolling$,
119
merge(catsClick$, meatsClick$).pipe(filter(c => c !== category))
120
)
121
),
122
// for demo purposes only
123
finalize(() => pollingStatus.innerHTML = 'Stopped')
124
)
125
}
126
127
// Handle Form Updates
128
catsClick$
129
.subscribe((category: RequestCategory) => {
130
requestCategory = category;
131
catImage.style.display = 'block';
132
text.style.display = 'none';
133
});
134
135
meatsClick$
136
.subscribe((category: RequestCategory) => {
137
requestCategory = category;
138
catImage.style.display = 'none';
139
text.style.display = 'block';
140
});
141
142
// Start Polling
143
fromEvent(startButton, 'click')
144
.pipe(
145
// for demo purposes only
146
tap(_ => pollingStatus.innerHTML = 'Started'),
147
mergeMap(_ => watchForData(requestCategory))
148
)
149
.subscribe();
Copied!

Operators Used

Example 2: Simple http polling

This recipe demonstrates polling an HTTP endpoint using repeat. It waits for 3 seconds following the response to poll again. Code below is simplifed to demonstrate bare bones of solution but link below contains verbose logging and error handling.
1
// RxJS v6+
2
import { of } from 'rxjs';
3
import { delay, tap, mergeMap, repeat } from 'rxjs/operators';
4
5
const fakeDelayedRequest = () => of(new Date()).pipe(delay(1000));
6
7
const display = response => {
8
document.open();
9
document.write(response);
10
};
11
12
const poll = of({}).pipe(
13
mergeMap(_ => fakeDelayedRequest()),
14
tap(display),
15
delay(3000),
16
repeat()
17
);
18
19
poll.subscribe();
Copied!
Last modified 1yr ago