├── README.md
├── assets
├── intro-full-rxjs.gif
├── intro-rxjs.gif
├── rx-concept.gif
└── vs-opt.gif
├── intro.html
├── js
├── vs-exec.js
├── vs-opt.js
├── vs-values.js
├── vs.js
└── world-clock-pm.js
├── promise-observable.html
├── terminolgy.html
├── vs.html
├── world-clock-pm.html
└── worldclock
├── bangkok.js
├── greenwich.js
├── japan.js
├── main.js
└── rx.html
/README.md:
--------------------------------------------------------------------------------
1 | # Introduction to Reactive Programming
2 |
3 | This is part of session in BKK.JS#19 event, 27 Jan 2024 at SCB Tech Siam Paragon
4 |
5 | ## Rx Terminology
6 | "reactive" and "propagation of change"
7 | ```
8 | Rx = Observables + LINQ + Schedulers
9 | ```
10 |
11 | ## Real world example
12 |
13 | This is case use World Clock as real world example
14 |
15 | ### How to
16 |
17 | Run `worldclock/rx.html`
18 |
19 | [code]
20 |
21 |
22 | ## Presentation Link
23 |
24 |
25 | canva
26 |
27 |
28 |
29 | [code]: (worldclock/rx.html)
30 |
--------------------------------------------------------------------------------
/assets/intro-full-rxjs.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viruskizz/bkkjs-reactive-programming/4502f3ccac71627f48ddcede6f00d8318a106d2c/assets/intro-full-rxjs.gif
--------------------------------------------------------------------------------
/assets/intro-rxjs.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viruskizz/bkkjs-reactive-programming/4502f3ccac71627f48ddcede6f00d8318a106d2c/assets/intro-rxjs.gif
--------------------------------------------------------------------------------
/assets/rx-concept.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viruskizz/bkkjs-reactive-programming/4502f3ccac71627f48ddcede6f00d8318a106d2c/assets/rx-concept.gif
--------------------------------------------------------------------------------
/assets/vs-opt.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viruskizz/bkkjs-reactive-programming/4502f3ccac71627f48ddcede6f00d8318a106d2c/assets/vs-opt.gif
--------------------------------------------------------------------------------
/intro.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Introduction Reactive Programing
7 |
8 |
9 |
10 |
27 |
28 |
--------------------------------------------------------------------------------
/js/vs-exec.js:
--------------------------------------------------------------------------------
1 | var promise = new Promise(resolve => {
2 | console.log('construct promise');
3 | resolve("pm: Good Geek Club");
4 | });
5 |
6 | var observable$ = new rxjs.Observable(observer => {
7 | console.log('construct observable');
8 | observer.next("rx: Good Geek Club");
9 | observer.complete();
10 | });
11 |
--------------------------------------------------------------------------------
/js/vs-opt.js:
--------------------------------------------------------------------------------
1 | var promise = new Promise(resolve => {
2 | resolve('pm: Good Geek Club');
3 | resolve('ft: BKK.JS');
4 | })
5 | promise
6 | .then(res => res.includes('pm') ? res: null)
7 | .then(res => res + ' [opt]')
8 | .then(res => new Promise(resolve => setTimeout(() => resolve(res), 3000)))
9 | .then(res => console.log(res));
10 |
11 |
12 | var { Observable, map, delay, filter } = rxjs;
13 |
14 | var observable$ = new Observable(observer => {
15 | observer.next("rx: Good Geek Club");
16 | observer.next("rx: 42 Bangkok");
17 | observer.next("ft: BKK.JS");
18 | observer.next("rx: LSEG");
19 | observer.complete();
20 | });
21 | observable$.pipe(
22 | filter(res => res.includes('rx')),
23 | map(res => res + ' [opt]'),
24 | delay(3000)
25 | ).subscribe(res => console.log(res))
--------------------------------------------------------------------------------
/js/vs-values.js:
--------------------------------------------------------------------------------
1 | var promise = new Promise(resolve => {
2 | resolve("pm: Good Geek Club");
3 | resolve("pm: 42 Bangkok");
4 | resolve("pm: LSEG");
5 | });
6 | promise.then(res => console.log(res));
7 |
8 | var observable$ = new rxjs.Observable(observer => {
9 | observer.next("rx: Good Geek Club");
10 | observer.next("rx: filter");
11 | observer.next("rx: 42 Bangkok");
12 | observer.next("rx: LSEG");
13 | observer.complete();
14 | });
15 | observable$.subscribe(res => console.log(res));
--------------------------------------------------------------------------------
/js/vs.js:
--------------------------------------------------------------------------------
1 | const { Observable, map, delay, filter } = rxjs;
2 | window.onload = () => {
3 | promise.exec();
4 | rx.exec();
5 | promise.values();
6 | rx.values();
7 | promise.opt();
8 | rx.opt();
9 | }
10 | const promise = {
11 | exec: () => {
12 | const promise = new Promise(resolve => {
13 | console.log('construct promise');
14 | appendList('pm-list-exec', 'construct promise');
15 | resolve("pm: Good Geek Club");
16 | });
17 | },
18 | values: () => {
19 | const promise = new Promise(resolve => {
20 | resolve("pm: Good Geek Club");
21 | resolve("pm: 42 Bangkok");
22 | resolve("pm: LSEG");
23 | });
24 | promise.then(res => {
25 | console.log(res);
26 | appendList('pm-list-values', res);
27 | });
28 | },
29 | opt: () => {
30 | const promise = new Promise(resolve => {
31 | resolve('pm: Good Geek Club');
32 | resolve('ft: BKK.JS');
33 | })
34 | promise
35 | .then(res => res.includes('pm') ? res: null)
36 | .then(res => res + ' [opt]')
37 | .then(res => new Promise(resolve => setTimeout(() => resolve(res), 3000)))
38 | .then(res => appendList('pm-list-opt', res));
39 | }
40 | }
41 | const rx = {
42 | exec: () => {
43 | const observable$ = new Observable(observer => {
44 | console.log('construct observable');
45 | appendList('rx-list-exec', 'construct observable');
46 | observer.next("rx: Good Geek Club");
47 | observer.complete();
48 | });
49 | },
50 | values: () => {
51 | const observable$ = new Observable(observer => {
52 | observer.next("rx: Good Geek Club");
53 | observer.next("rx: filter");
54 | observer.next("rx: 42 Bangkok");
55 | observer.next("rx: LSEG");
56 | observer.complete();
57 | });
58 | observable$.subscribe((res) => {
59 | console.log(res);
60 | appendList('rx-list-values', res);
61 | });
62 | },
63 | opt: () => {
64 | const observable$ = new Observable(observer => {
65 | observer.next("rx: Good Geek Club");
66 | observer.next("rx: 42 Bangkok");
67 | observer.next("ft: BKK.JS");
68 | observer.next("rx: LSEG");
69 | observer.complete();
70 | });
71 | observable$.pipe(
72 | filter(res => res.includes('rx')),
73 | map(res => res + ' [opt]'),
74 | delay(3000)
75 | ).subscribe(res => appendList('rx-list-opt', res))
76 | }
77 | }
78 | function appendList(divId, data) {
79 | const div = document.getElementById(divId);
80 | const list = document.createElement('li');
81 | list.innerHTML = data;
82 | div.appendChild(list);
83 | }
--------------------------------------------------------------------------------
/js/world-clock-pm.js:
--------------------------------------------------------------------------------
1 | const { interval, map, scan } = rxjs;
2 | const timezones = [
3 | {id: 'greenwich', diff: 0},
4 | {id: 'bangkok', diff: 7 * 60 * 60},
5 | {id: 'japan', diff: 9 * 60 * 60},
6 | ]
7 | let unixTimestamp = Math.floor(new Date().getTime() / 1000);
8 |
9 | // interaval function do something
10 | setInterval(() => {
11 | ++unixTimestamp;
12 | for (const tz of timezones) {
13 | const el = document.getElementById(tz.id)
14 | el.innerHTML = datetimeText(time + tz.diff);
15 | }
16 | }, 1000);
17 |
18 | function datetimeText(time) {
19 | const s = time % 60
20 | const m = Math.floor((time / 60) % 60);
21 | const h = Math.floor(time / (60 * 60) % 24);
22 | const f0 = (t) => (t < 9 ) ? `0${t}`: t
23 | return `${f0(h)}:${f0(m)}:${f0(s)}`;
24 | }
25 |
--------------------------------------------------------------------------------
/promise-observable.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Promise vs Observable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Promise vs Observable
14 |
15 |
16 |
Execution
17 |
18 |
22 |
23 |
Observable
24 |
25 |
26 |
27 |
28 |
29 |
30 |
Single vs Multiple values
31 |
32 |
36 |
37 |
Observable
38 |
39 |
40 |
41 |
42 |
43 |
44 |
Operators
45 |
46 |
50 |
51 |
Observable
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/terminolgy.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Introduction Reactive Programing
7 |
8 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/vs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Promise vs Observable on console
7 |
8 |
9 |
10 |
11 |
12 |
13 | Debug console only
14 |
15 |
--------------------------------------------------------------------------------
/world-clock-pm.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | World Clock Rx
7 |
8 |
9 |
10 |
11 |
12 |
13 |
World Clock Application
14 |
15 |
16 |
Japan
17 |
GMT+9
18 |
19 | 00:00:00
20 |
21 |
22 |
23 |
Greenwich
24 |
GMT
25 |
26 | 00:00:00
27 |
28 |
29 |
30 |
Bangkok
31 |
GMT+7
32 |
33 | 00:00:00
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/worldclock/bangkok.js:
--------------------------------------------------------------------------------
1 | import { gmtClock$, timestampText, HR_SECOND } from './main.js'
2 | const { map } = rxjs;
3 |
4 | gmtClock$.pipe(
5 | map(t => t + 7 * HR_SECOND)
6 | ).subscribe(time => {
7 | const el = document.getElementById('bangkok')
8 | el.innerHTML = timestampText(time);
9 | })
10 |
--------------------------------------------------------------------------------
/worldclock/greenwich.js:
--------------------------------------------------------------------------------
1 | import { gmtClock$, timestampText, HR_SECOND } from './main.js'
2 | const { map } = rxjs;
3 |
4 | gmtClock$.subscribe(time => {
5 | const el = document.getElementById('greenwich')
6 | el.innerHTML = timestampText(time);
7 | })
8 |
--------------------------------------------------------------------------------
/worldclock/japan.js:
--------------------------------------------------------------------------------
1 | import { gmtClock$, timestampText, HR_SECOND } from './main.js'
2 | const { map } = rxjs;
3 |
4 | gmtClock$.pipe(
5 | map(t => t + 9 * HR_SECOND)
6 | ).subscribe(time => {
7 | const el = document.getElementById('japan')
8 | el.innerHTML = timestampText(time);
9 | })
10 |
--------------------------------------------------------------------------------
/worldclock/main.js:
--------------------------------------------------------------------------------
1 | const { interval, scan } = rxjs;
2 |
3 | /*
4 | * Emit current unixtimestamp every second
5 | * Create current unixtimestamp as initial value
6 | */
7 | const gmtClock$ = interval(1000).pipe(
8 | scan(ts => ++ts, Math.floor(new Date().getTime() / 1000))
9 | );
10 |
11 | const HR_SECOND = 60 * 60;
12 |
13 | const timestampText = (time) => {
14 | const s = time % 60
15 | const m = Math.floor((time / 60) % 60);
16 | const h = Math.floor(time / (60 * 60) % 24);
17 | const f0 = (t) => (t < 9 ) ? `0${t}`: t
18 | return `${f0(h)}:${f0(m)}:${f0(s)}`;
19 | }
20 |
21 | export { gmtClock$, HR_SECOND, timestampText }
22 |
23 | /**
24 | * 1 data stream split to 3 data stream
25 | */
26 | // gmtTime$.pipe(
27 | // switchMap(time => from(timezones).pipe(map(tz => ({...tz, time}))))
28 | // ).subscribe(tz => {
29 | // const el = document.getElementById(tz.id)
30 | // el.innerHTML = datetimeText(tz.time + tz.diff);
31 | // });
--------------------------------------------------------------------------------
/worldclock/rx.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | World Clock Rx
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
World Clock Application
18 |
19 |
20 |
Japan
21 |
GMT+9
22 |
23 | 00:00:00
24 |
25 |
26 |
27 |
Greenwich
28 |
GMT
29 |
30 | 00:00:00
31 |
32 |
33 |
34 |
Bangkok
35 |
GMT+7
36 |
37 | 00:00:00
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------