😎

ReactでWebWorkerをサクッと使う

2021/07/08に公開

はじめに

業務やちゃんと開発したいものではなく、技術を試したりするときにworker-loader等の導入、TypeScriptでの対応をやるのが面倒だった。
サクッと使いたいだけなのに...という時に使うためだけです。

※ 業務や複数人の開発、お遊び等ではない個人開発ではちゃんとworker-loaderやcomlinkの導入・TypeScriptで型安全な開発をしましょう。

実装

WebWorkerの用意

まずはWeb Workerの実装から。
適当に受け取った数値分のループを行います。

loop.worker.js
export default () => {
    self.onmessage = (event) => {
        const max = event.data;

        for (let i = 1; i <= max; i++) {
            console.log(`${i}回目`);
        }

        postMessage('finish');
    }
}

WebWorkerを読み込む

上記で作成したWorkerを読み込むクラスを作ります。

worker-loader.js
export defautlt class WorkerLoader extends Worker {
    
    constructor(worker, onMessage) {
        const code = worker.toString();
        const blob = new Blob([`(${code})()`]);
        const workerUrl = URL.createObjectURL(blob);

        const instance = new Worker(workerUrl);
        
        if (instance) {
            URL.revokeObjectURL(workerUrl);
        }

        if (onMessage) {
            instance.onmessage = onMessage;
        }

        return instance;
    }
}

vanilla JSで使う

index.js
import WorkerLoader from './lib/worker-loader.js';
import LoopWorker from './workers/loop.worker.js';

(function () {
    const loopWorker = new WorkerLoader(LoopWorker, (message) => {
        console.log(`message from worker => ${message.data}`);
    });

    loopWorker.postMessage(100000);
})()

Reactで使う

App.jsx
import WorkerLoader from './lib/worker-loader';
import LoopWorker from './workers/loop.worker';


const App = () => {
    const worker = new WorkerLoader(LoopWorker);

    const handleClick = () => {
        worker.postMessage(100000);
    }

    useEffect(() => {
        worker.onmessage = (message) => {
            console.log(`message from worker => ${message.data}`);
        }

        return () => {
            worker.terminate();
        }
    }, []);


    return <button onClick={handleClick}>post message</button>;
}

Discussion