Search code examples
javascriptvue.jsweb-applicationsfrontendweb-worker

Is it possible to access Web Workers inside a .vue component


So I am thinking of creating this app which uses this web worker that i found which generates rubik's cube scrambles (it's actually a bit of an intensive process to generate a random state scramble, especially for bigger cubes, so web workers are necessary for this scenario). And i am wondering if it would be possible to access this web worker from inside a vue component (would there be any issues with serving the worker file or accessing it. If it is possible, how would i make it work?


Solution

  • Yes, you can, here is a demo:

    Vue.component('my-component', {
      template: '#my-component',
      data() {
        return {
          cube: '-- no data yet --',
          worker: null
        };
      },
      created() {
        this.initWorker();
      },
      beforeDestroy() {
        this.destroyWorker();
      },
      methods: {
        initWorker() {
          // Here, just for this demo to work, I'm not using an external file
          // for the worker. Instead, I use a Blob. It's still a real Worker!
          // See https://stackoverflow.com/a/6454685/1913729
          const scriptBlob = new Blob(
            [ document.querySelector('#worker-script').textContent ],
            { type: "text/javascript" }
          );
          this.worker = new Worker(window.URL.createObjectURL(scriptBlob));
          this.worker.onmessage = e => this.onCubeReady(e.data);
        },
        destroyWorker() {
          this.worker.terminate();
        },
        scrambleCube() {
          this.cube = '-- Scrambling cube... --'
          this.worker.postMessage('Gimme a cube');
        },
        onCubeReady(cube) {
          this.cube = cube;
        }
      }
    });
    
    var vm = new Vue({
      el: '#app'
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.min.js"></script>
    
    <div id="app">
      <my-component></my-component>
    </div>
    
    <template id="my-component">
      <div>
        <button @click="scrambleCube">Scramble cube</button>
        <pre>{{cube}}</pre>
      </div>
    </template>
    
    <!-- This is just for the demo, and won't be parsed
         because of type="javascript/worker".
         we load it into a Blob to make it a worker -->
    <script type="javascript/worker" id="worker-script">
    self.addEventListener("message", onMessageReceive);
    
    function onMessageReceive(e) {
      console.log(`Worker received a message`);
      const res = heavyProcessing();
      self.postMessage(res);
    }
    
    function heavyProcessing() {
      const endTime = Date.now() + 2000;
      while (Date.now() < endTime) {}
      return 'CUBE MADE BY A WORKER';
    }
    </script>