Running in Parallel: NgRx with WebAssembly, Web Workers and Worklets

Running in Parallel: NgRx with WebAssembly, Web Workers and Worklets

UI is freezing, one of the CPU cores burning, you can do nothing at the moment. The only thing you can hear right now is the howl cooler. The only perception you can feel is as hot as a hell metal case of the laptop. This is not a horror story or a thriller. Just a modern web app that runs everything in the main JS thread. The only way to be alive - run code in parallel.

4f0880beebecf17d29eb709246055e14?s=128

Vitalii Bobrov

May 27, 2019
Tweet

Transcript

  1. Running in Parallel NgRx with WebAssembly, Web Workers and Worklets

  2. Running in Parallel All the Buzz Words, I ever heard

  3. Running in Parallel The Way to Performance

  4. Vitalii Bobrov • Lead SW Engineer @ EPAM • Angular

    Wrocław organizer • Angular in Depth contributor • Performance warrior @bobrov1989 https://bobrov.dev
  5. I brought something interesting to share

  6. Topics • Parallel Computations • Web Workers • Worklets •

    Web Assembly & AssemblyScript
  7. Parallel Computations

  8. Border Control

  9. Passport Control Border Line One Thread

  10. Passport Control Border Line One Thread

  11. Passport Control Border Line One Thread

  12. Passport Control Border Line Async

  13. Passport Control Border Line Async

  14. Passport Control Border Line Async

  15. Passport Control Border Line Async

  16. Passport Control Border Line Async

  17. Parallel doesn’t mean X times faster

  18. Passport Control Border Line Multi Thread Passport Control Line

  19. Passport Control Border Line Multi Thread Passport Control Line

  20. Passport Control Border Line Multi Thread Passport Control Line

  21. Thread is not equal to CPU core

  22. All Passports Border Line Worker / Worklet EU Passports Line

  23. All Passports Border Line Worker / Worklet EU Passports Line

  24. All Passports Border Line Worker / Worklet EU Passports Line

  25. Complicate Code

  26. Web Workers

  27. UI Blocking

  28. Disappointed User

  29. const worker = new Worker('path/to/worker.js'); Init Web Worker

  30. Full-Duplex Communication Main Thread Worker Thread worker.postMessage('data'); worker.addEventListener('message', (event: MessageEvent)

    => { console.log(event.data); }); addEventListener('message', (event: MessageEvent) => { console.log(event.data); }); postMessage('response');
  31. ng generate worker my-web-worker Web Worker with CLI v8+

  32. Worker implementation addEventListener('message', ({ data }) => { data.sort((a, b)

    => { for (let i = 0; i < 10000; i++) { const sum = i * Math.random() * 10; } return a.order - b.order; }); postMessage(data); });
  33. NgRx Power

  34. NgRx Effects @Effect({ dispatch: false }) sortWorkerThread$ = this.actions$.pipe( ofType(WebWorkerActionTypes.WebWorkerSort),

    map(({ payload }) => this.workerInstance.postMessage(payload.items) ));
  35. NgRx Effects @Effect() workerSortSuccess$ = fromEvent(this.workerInstance, 'message') .pipe(map((event: MessageEvent) =>

    new WorkerSortSuccess({ items: event.data })));
  36. Off-thread

  37. Worklets

  38. Available Worklets • Paint • Animation • Layout • Audio

  39. Paint API

  40. Half-Duplex Communication Main Thread Worklet Thread class CirclesPainter { static

    get inputProperties() { return [ '--circles-offset', '--circles-count', '--circles-opacity' ]; } } element.style .setProperty('--circles-offset', 10);
  41. Half-Duplex Communication Main Thread Worklet Thread class CirclesPainter { static

    get inputProperties() { return [ '--circles-offset', '--circles-count', '--circles-opacity' ]; } } :root { --circles-count: 2; --circles-offset: 10; --circles-opacity: 1; }
  42. Create Worklet class MyPaint { paint(ctx: CanvasRenderingContext2D) { ctx.beginPath(); ctx.arc(x,

    y, outerRadius, 0, Math.PI * 2, false); ctx.arc(x, y, innerRadius, 0, Math.PI * 2, true); ctx.fill(); } } registerPaint('my-paint', MyPaint);
  43. Load Worklet if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('my-paint'); }

  44. Use Worklet .circle { background: #999 paint(my-paint); }

  45. QR Code

  46. Chart

  47. WebAssembly

  48. WASM - binary instruction format for a stack-based VM

  49. WHAT ?!

  50. WTF ?!

  51. WAT WebAssembly Text Format

  52. Devs are Good in Naming

  53. Available Options • Rust • C/C++ • TypeScript via AssemblyScript

  54. Install yarn add AssemblyScript/assemblyscript

  55. Init npx asinit .

  56. Build yarn asbuild

  57. Basic function import "allocator/tlsf"; export function add(a: i32, b: i32):

    i32 { return a + b; }
  58. Load WASM module import { instantiateStreaming, ASUtil } from "assemblyscript/lib/loader";

    interface MyApi { add(a: number, b: number): number; } const imports: any = {}; async function main(): void { var interop: ASUtil<MyApi> = await instantiateStreaming<MyApi>(fetch("../build/untouched.wasm"), imports); console.log("The result is:", interop.add(1, 2)); }
  59. Running in Parallel Performance of Heavy Tasks

  60. @bobrov1989 https://bobrov.dev Vitalii Bobrov