9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

はじめに

React Hooksを使うと、非同期処理を比較的簡単に書くことができます。つまり、async/awaitをhooks内に隠蔽することができます。Web Workerを手軽に利用する有名なライブラリとしてcomlinkがありますが、WebWorkerとの通信は非同期であるためawaitをつけなければいけません。そこで、より手軽に扱えるReact Hooks専用のWeb Workerラッパーを紹介します。

react-hooks-worker

リポジトリはこちらです。

https://github.com/dai-shi/react-hooks-worker

このライブラリでは、Web Workerとの通信をstateを介して行うため、async/awaitをあまり意識する必要がないことが特徴です。

Web Workerを手軽に使うには、bundlerのサポートが重要です。各種プラグイン等がありますが、今回使用したのはwebpackのworker-pluginです。これにより、workerでも外部ライブラリが使えるようになります(本記事での使用例の紹介は無し)。

使用例

フィボナッチ数を計算する例を紹介します。まずは、workerの実装です。

// slow_fib.worker.js:

import { exposeWorker } from 'react-hooks-worker';

const fib = i => (i <= 1 ? i : fib(i - 1) + fib(i - 2));

exposeWorker(fib);

次に、これを利用するReactコンポーネントの実装です。

// app.js:

import React from 'react';
import { useWorker } from 'react-hooks-worker';

const createWorker = () => new Worker('./slow_fib.worker', { type: 'module' });

const CalcFib = ({ count }) => {
  const { result, error } = useWorker(createWorker, count);
  if (error) return <div>Error: {error}</div>;
  return <div>Result: {result}</div>;
};

const App = () => (
  <div>
    <CalcFib count={5} />
  </div>
);

これだけで、workerが使えるようになります。重い計算処理(かつ、結果が小さい場合)は、どんどんworkerにoffloadしましょう。

発展的な使い方

上記の例ではworkerの実装は単純な関数でしたが、実は、非同期関数やgeneratorでも動きます。列挙すると使えるパターンは下記になります。

  • sync function
  • async function
  • sync generator function
  • async generator function

参考までに、async generatorでフィボナッチ数の計算過程をゆっくりと出力するworker関数を載せます。

// fib-steps.worker.js

import { exposeWorker } from 'react-hooks-worker';

async function* fib(x) {
  let x1 = 0;
  let x2 = 1;
  let i = 0;
  while (i < x) {
    yield `(calculating...) ${x1}`;
    await new Promise(r => setTimeout(r, 100));
    [x1, x2] = [x2, x1 + x2];
    i += 1;
  }
  yield x1;
}

exposeWorker(fib);

workerの処理をプログレッシブに表示する場合などにこのパターンが使えるのではないでしょうか。

おわりに

本ライブラリではworkerは関数として表現されますが、comlinkは様々なオブジェクトをサポートしています。よく紹介されるのはworkerをclassとして実装する例ですが、このパターンを好む人がいることを知りました。react-hooks-workerでも様々なパターンをサポートすることが今後の改題の一つになりそうです。

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?