Web Workers: A musical intro

Web Workers: A musical intro

55c3671e959e903a7880eaf0cf61f3e4?s=128

Ritesh Kumar

August 22, 2018
Tweet

Transcript

  1. Web Workers A musical intro @ritz078 Ritesh Kumar, Lead Software

    Engineer, Anarock
  2. for (let i = 0; i !<= 1000000000; i!++) {

    Math.random(); }
  3. None
  4. Traditionally web browsers only have a single thread (is it?).

  5. Code JS Main Thread

  6. Doesn’t Block the thread Blocks the thread

  7. The code we write Web APIs Core JS

  8. The code we write Web APIs Core JS Blocking +

    Non blocking Blocking
  9. • Language syntax • Built-in objects and functions • Global

    objects • Prototype based inheritance system • Error handling mechanisms • document • requestIdleCallback • requestAnimationFrame • setTimeout • setInterval • Promises • And many more Web APIs Core JavaScript
  10. Browser’s thread JS Main thread Non blocking web APIs Blocking

    JS
  11. Piano by Adrien Coquet from the Noun Project

  12. None
  13. • Loading MIDI files • Playing music • Visualization

  14. Loading MIDI files

  15. import { parse } from “midiconvert"; const file = new

    FileReader(); file.onload = () !=> { !// heavy computation const parsedMidi = parse(file.result); };
  16. import { parse } from “midiconvert"; const file = new

    FileReader(); file.onload = () !=> { !// heavy computation const parsedMidi = parse(file.result); }; File loading + Parsing
  17. Non blocking web APIs Blocking JS Can we achieve concurrency

    for them ?
  18. Web Workers

  19. Web Workers is a simple means for web content to

    run scripts in background threads.
  20. Non blocking web APIs Blocking JS Worker Thread

  21. Non blocking web APIs Blocking JS Worker Thread Browser thread

    JS Main Thread
  22. postMessage API

  23. We can create multiple web workers.

  24. Usage

  25. const myWorker = new Worker('worker.js');

  26. !// main.js const myWorker = new Worker('worker.js'); myWorker.postMessage("sending data to

    worker"); myWorker.onmessage = function(e) { console.log('Message received from worker'); } Spawn a worker
  27. !// main.js const myWorker = new Worker('worker.js'); myWorker.postMessage("sending data to

    worker"); myWorker.onmessage = function(e) { console.log('Message received from worker'); } Send message to worker
  28. !// worker.js onmessage = function(e) { console.log('Message received from main

    script'); var workerResult = 'Result: ' + (e.data); console.log('Posting message back to main script'); postMessage(workerResult); } Receive message in worker
  29. !// worker.js onmessage = function(e) { console.log('Message received from main

    script'); var workerResult = 'Result: ' + (e.data); console.log('Posting message back to main script'); postMessage(workerResult); } Send message to the main script
  30. Receive message from worker !// main.js const myWorker = new

    Worker('worker.js'); myWorker.postMessage("sending data to worker"); myWorker.onmessage = function(e) { console.log('Message received from worker'); }
  31. • Loading files • Playing music • Visualization

  32. File upload

  33. !// This is possible due to the usage of worker-loader

    in webpack. !// You can't do this without that. Only importScripts works. import { parse } from “midiconvert"; const file = new FileReader(); file.onload = () !=> { !// heavy computation const parsedMidi = parse(file.result); self.postMessage({ data: parsedMidi }); }; self.onmessage = e !=> { file.readAsArrayBuffer(e.data); };
  34. Playing Music = Scheduling Notes + Playing those notes

  35. Playing Music = Scheduling Notes + Playing those notes WebAudio

    API. Audio plays in different thread by default.
  36. Challenges in scheduling notes. • Minimum time precision in JS

    clock is of 1ms. • The JS timers (setTimeout, setInterval) call can be delayed if the thread is blocked.
  37. • Minimum time precision in JS clock is of 1ms.

    - a combination of setTimeout and audio hardware scheduling. • The JS timers (setTimeout, setInterval) call can be delayed if the thread is blocked. (workers) Challenges in scheduling notes.
  38. Playing Music = Scheduling Notes + Playing those notes WebAudio

    API. Audio plays in different thread by default. WebAudio API’s time + setTimeOut + Web Workers
  39. Visualization Sync

  40. None
  41. Canvas

  42. Why separate timer ?

  43. Canvas is scriptable. So ?

  44. Main thread const canvasWorker = new Worker("./canvas-worker"); const offscreenCanvas =

    document .getElementById(“canvas”) .transferControlToOffscreen(); canvasWorker.postMessage(offscreenCanvas, [offscreenCanvas]);
  45. Main thread What’s this ? const canvasWorker = new Worker("./canvas-worker");

    const offscreenCanvas = document .getElementById(“canvas”) .transferControlToOffscreen(); canvasWorker.postMessage(offscreenCanvas, [offscreenCanvas]);
  46. postMessage API

  47. Serialization Deserialization postMessage

  48. Serialization Deserialization postMessage SLOW

  49. Tranferables Objects

  50. Transferring Memory - ArrayBuffers

  51. Transferring Memory - ArrayBuffers No more accessible accessible

  52. Shared Array Buffers

  53. Usage worker.postMessage(message, [transferableList]);

  54. http://html5-demos.appspot.com/static/workers/transferables/index.html Benchmark 32 MB Data Serialization - 302ms Transferable Objects

    - 6.6ms
  55. Main thread The main thread has tranferred this “transferable” to

    worker and has no control over it anymore. const canvasWorker = new Worker("./canvas-worker"); const offscreenCanvas = document .getElementById(“canvas”) .transferControlToOffscreen(); canvasWorker.postMessage(offscreenCanvas, [offscreenCanvas]);
  56. In worker thread, we get the canvas. import { Visualizer

    } from "@utils/Visualizer"; self.onmessage = e !=> { const canvas = e.data; const visualizer = new Visualizer(canvas); };
  57. More ?

  58. Write Mode

  59. Write Mode • Play using 128 sounds. • Record. •

    Save MIDI. • Connect a keyboard/Piano.
  60. Control the keyboard from the app or vice versa.

  61. Thank You @ritz078