Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc)...
Transcript of Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc)...
![Page 1: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/1.jpg)
ObservableEnhancing EventTarget
![Page 2: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/2.jpg)
Observable● Composable enhancement of Event Target● Allows events to be coordinated in async functions
![Page 3: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/3.jpg)
Consuming an EventTarget (ET) as an Observable
domElement. on('mousemove'). forEach(e => console.log(e));
![Page 4: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/4.jpg)
Consuming ET as Observable with Capture Options
domElement. on('mousemove', { capture: true }). forEach(e => console.log(e));
![Page 5: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/5.jpg)
Consuming ET as Observable with Cancellationconst { token, cancel } = CancelToken.source();
const subscriptionPromise = domElement.
on('mousemove', { capture: true }).forEach(e => console.log(e), token);
// unsubscribe latercancel();
rejects
![Page 6: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/6.jpg)
Composing Observables
![Page 7: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/7.jpg)
Composing Observables● Observables can be composed like Arrays (ex. map, filter, etc)● Composition can be enabled with user-land libraries like lodash● Future plan to add popular functions to Observable prototype
![Page 8: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/8.jpg)
Contrived composition exampleimport { map, filter } from 'lodash-for-events';
function mouseMoveCoordinatesInRect(element, rect) { let events = element.on('mousemove'); let coordinates = map(events, e => ({ x: e.clientX, y: e.clientY }));
return filter(coordinates, ({ x, y }) => { return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom; });}
mouseMoveCoordinatesInRect(document.body, new DOMRect(0, 0, 100, 100)). forEach(coords => drawPixelAt(coords));
![Page 9: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/9.jpg)
If we improve Observable.prototype this becomes...function mouseMoveCoordinatesInRect(element, rect) { return element.on('mousemove'). map(e => ({ x: e.clientX, y: e.clientY })). filter(coordinates, ({ x, y }) => { return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
});}
![Page 10: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/10.jpg)
Composition Use Case: Draw Signature on Canvas
async function drawSignature(signatureCanvas, cancelToken) { await.cancelToken = cancelToken;
// snip...
}
![Page 11: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/11.jpg)
import { _ } from 'lodash-for-events';
async function drawSignature(signatureCanvas, cancelToken) { await.cancelToken = cancelToken; const sigMouseDowns = _(signatureCanvas.on('mousedown'));
// snip...
}
Composition with user-land libraries
![Page 12: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/12.jpg)
import { _ } from 'lodash-for-events';
async function getSignature(signatureCanvas, cancelToken) { await.cancelToken = cancelToken; const toPoint = e => ({ x: e.offsetX, y: e.offsetY }); const sigMouseDowns = _(signatureCanvas.on('mousedown')).map(toPoint);
// snip...
}
Composition: Map Function
![Page 13: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/13.jpg)
import { _ } from 'lodash-for-events';
async function getSignature(signatureCanvas, cancelToken) { await.cancelToken = cancelToken; const toPoint = e => ({ x: e.offsetX, y: e.offsetY }); const sigMouseDowns = _(signatureCanvas.on('mousedown')).map(toPoint);
let lastPointClicked = await sigMouseDowns.first(cancelToken);
// snip...
}
Composition: Await Events with First
![Page 14: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/14.jpg)
import { _ } from 'lodash-for-events';
async function getSignature(signatureCanvas, cancelToken) { await.cancelToken = cancelToken; const toPoint = e => ({ x: e.offsetX, y: e.offsetY }); const sigMouseDowns = _(signatureCanvas.on('mousedown')).map(toPoint); const sigMouseMoves = _(signatureCanvas.on('mousemove')).map(toPoint); const sigMouseUps = _(signatureCanvas.on('mouseup')).map(toPoint); let lastPointClicked = await sigMouseDowns.first(cancelToken);
await sigMouseMoves.takeUntil(sigMouseUps). forEach( point => {
strokeLine(signatureCanvas, lastPointClicked.x, lastPointClicked.y, point.x, point.y); lastPointClicked = point; }, cancelToken);
}
Composition: Handle Event 'til another Event Occurs
![Page 15: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/15.jpg)
Using Events in Async Workflows
![Page 16: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/16.jpg)
Example: Form that collects e-signature
Mortgage Form
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras mattis et
purus ac iaculis. Aliquam non sagittis lectus. Mauris euismod lectus
accumsan leo scelerisque viverra. Nulla ut metus sed velit condimentum
molestie a at felis. Aenean fermentum fermentum erat sit amet mollis.
Etiam porttitor justo id euismod euismod. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas. Donec
sagittis mattis neque cursus gravida. Nam molestie erat in felis auctor,
quis fermentum diam porttitor. Duis non augue pulvinar, viverra metus
consectetur, lobortis eros. In egestas risus non turpis commodo sodales.
Phasellus id purus condimentum orci maximus facilisis. Curabitur
fermentum maximus risus, a ullamcorper mi faucibus at.
Signature
![Page 17: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/17.jpg)
Example: Form that collects e-signature
Mortgage Form
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras mattis et
purus ac iaculis. Aliquam non sagittis lectus. Mauris euismod lectus
accumsan leo scelerisque viverra. Nulla ut metus sed velit condimentum
molestie a at felis. Aenean fermentum fermentum erat sit amet mollis.
Etiam porttitor justo id euismod euismod. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas. Donec
sagittis mattis neque cursus gravida. Nam molestie erat in felis auctor,
quis fermentum diam porttitor. Duis non augue pulvinar, viverra metus
consectetur, lobortis eros. In egestas risus non turpis commodo sodales.
Phasellus id purus condimentum orci maximus facilisis. Curabitur
fermentum maximus risus, a ullamcorper mi faucibus at.
Signature
Enter your Signature
OK Cancel
![Page 18: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/18.jpg)
Example: Form that collects e-signature
Mortgage Form
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras mattis et
purus ac iaculis. Aliquam non sagittis lectus. Mauris euismod lectus
accumsan leo scelerisque viverra. Nulla ut metus sed velit condimentum
molestie a at felis. Aenean fermentum fermentum erat sit amet mollis.
Etiam porttitor justo id euismod euismod. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas. Donec
sagittis mattis neque cursus gravida. Nam molestie erat in felis auctor,
quis fermentum diam porttitor. Duis non augue pulvinar, viverra metus
consectetur, lobortis eros. In egestas risus non turpis commodo sodales.
Phasellus id purus condimentum orci maximus facilisis. Curabitur
fermentum maximus risus, a ullamcorper mi faucibus at.
Signature
![Page 19: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/19.jpg)
Async Function: getSignature
Enter your Signature
OK Cancel
import { _ } from 'lodash-for-events';
async function getSignature(token) { const signatureDialog = createAndDisplaySignatureDialog(); try { const signatureCanvas = signatureDialog.querySelector('.signatureCanvas');
const okButton = signatureDialog.querySelector('.okbutton'); const cancelButton = signatureDialog.querySelector('.cancelbutton'); const ok = _(okButton.on('click')).first(token); const cancel = _(cancelButton.on('click')).first(token);
// concurrently handle signature draws, an ok click, and a cancel click return await Promise.race([ drawSignature(signatureCanvas, okButton, token), ok.then(() => signatureCanvas.toDataURL()), cancel.then(() => undefined)) ]); } finally { signatureDialog.remove(); }}
![Page 20: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/20.jpg)
Using Events in Async Functions: drawSignatureimport { _ } from 'lodash-for-events';
async function drawSignature(signatureCanvas, okButton, token) { await.cancelToken = cancelToken; const context = signatureCanvas.getContext('2d'); const toPoint = e => ({ x: e.offsetX, y: e.offsetY }); const sigMouseDowns = _(signatureCanvas.on('mousedown')).map(toPoint); const sigMouseMoves = _(signatureCanvas.on('mousemove')).map(toPoint); const sigMouseUps = _(signatureCanvas.on('mouseup')).map(toPoint);
while(true) { let lastPoint = await sigMouseDowns.first(token);
await sigMouseMoves.takeUntil(sigMouseUps). forEach( point => { strokeLine(context, lastPoint.x, lastPoint.y, point.x, point.y); okButton.disabled = false; lastPoint = point; }, token); }}
![Page 21: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/21.jpg)
Benefits of Observable● Coordinate event streams in async functions● takeUntil: combine multiple infinite event streams into a finite stream which
can be awaited● Can be adapted into Asynchronous Iterators
![Page 22: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/22.jpg)
Appendix
![Page 23: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/23.jpg)
Observable Classclass Observable<T> {
constructor(subscribeDefn: Function)
subscribe(observer: Observer, token: CancelToken): void
forEach(nextFn: Function, token: CancelToken): Promise
[Symbol.observable](): Observable
static of(...items): Observable
static from(ObservableLike: Object): Observable}
![Page 24: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/24.jpg)
Observer Interfaceinterface Observer {
next(value),
// try/else equivalentelse(error),
complete(value)
// receives object sent during unsubscription/cancellation // try/catch equivalent
catch(cancel)}
![Page 25: Observable - ES Discuss Observables Observables can be composed like Arrays (ex. map, filter, etc) Composition can be enabled with user-land libraries like lodash ... Contrived composition](https://reader031.fdocuments.in/reader031/viewer/2022021819/5ad5ec7b7f8b9a5d058dc729/html5/thumbnails/25.jpg)
Adapting EventTarget to ObservableEventTarget.prototype.on = function(name, options) { // constructor passed Observable.prototype.subscribe(observer, token) defn return new Observable((observer, token) => { const handler = e => { if (token.reason === undefined) { observer.next(e); } };
this.addEventListener(name, handler, options);
token.promise.then(cancel => { this.removeEventListener(name, handler, options); observer.catch(cancel); }); });}