👷

workerについてざっくり理解する

2022/10/19に公開

ファンタラクティブのエンジニアの 太田 です。
今までファンタラクティブのZennアカウントで記事を書いていましたが、Publicationができたのでこれからは自分のアカウントで書いていきます。

この記事はWorkerについての内容になります。
フロントエンド開発においてWorkerという単語をよくみかけるようになってきました。
私自身は今までほとんどWorkerを触ったことがありませんでした。
普段の開発でMSW (Mock Service Worker) を積極的に使用していますが、ほとんどService Workerを意識することはなく知識が不足しています。

https://mswjs.io/

Service WorkerはPWAの文脈においても関わってくると認識をしていますが、iOSとAndroid間のふるまいの差などにより導入を見送りつづけ、一度も実装をすることなく今までやってきてしまいました。(PWA自体あまり聞かなくなった気がする)

CloudflareなどのEdge Workerに興味が出てきたこともあり、今まで避けてきたWorkerについて調べ、自分なりに解釈した内容を書きます。

Workerの種類

  • Dedicated Worker
  • Shared Worker
  • Service Worker
  • Edge Worker

Dedicated Worker (専用ワーカー)


なんとなく理解したイメージ - Dedicated Worker

  • 呼び出し元からのみアクセス可能
  • postMessage、onmessageでメインスレッドとデータのやりとりをする

main.js

const worker = new Worker('worker.js')

worker.onmessage = (ev) => {
  console.log(ev.data)
}

worker.postMessage('hello')

worker.js

onmessage = (ev) => {
  console.log(ev.data)
  postMessage('world')
}

実行結果

hello // worker.js
world // main.js

Shared Worker (共有ワーカー)


なんとなく理解したイメージ - Shared Worker

  • 同じorigin内から呼び出し可能

main.js

const worker = new Worker('worker.js')

worker.port.onmessage = (ev) => {
  console.log(ev.data)
}

worker.start()

worker.port.postMessage('hello')

worker.js

onconnect = (ev) => {
  const port = ev.ports[0]

  port.addEventListener('message', (ev) => {
    console.log(ev.data)
    port.postMessage('world')
  })

  port.start()
}

実行結果

hello // worker.js
world // main.js

Shared Worker側のログはブラウザでフロントのログと一緒には出力されず、ブラウザで chrome://inspect/#workers を開くと出力されていました。

Service Worker


なんとなく理解したイメージ - Service Worker

  • registerして使用
  • serviceWorkerはひとつしか登録できない
  • メインスレッドと外部間の通信に割り込んだりキャッシュを使用できる

main.js

navigator.serviceWorker.register('/serviceWorker.js')

const channel = new MessageChannel()

channel.port1.onmessage = (ev) => {
  console.log(ev.data)
}

navigator.serviceWorker.controller?.postMessage('hello', [channel.port2])

serviceWorker.js

self.addEventListener('install', (ev) => {
  ev.waitUntil(self.skipWaiting())
})

self.addEventListener('activate', (ev) => {
  ev.waitUntil(self.clients.claim())
})

self.addEventListener('message', async (ev) => {
  console.log(ev.data)

  ev.ports[0].postMessage('world')
})

実行結果

hello // serviceWorker.js
world // main.js

Edge Worker


なんとなく理解したイメージ - Edge Worker

  • CDNで処理を行うWorker
  • CPU、メモリなどの制限がきつい傾向がある
  • HTTPリクエストをインターセプトし、処理して返すことができる

※CDNによって書き方が異なるのでコードは省略します。

あとがき

調べてみて改めてかなり奥が深い分野だと感じました。
記事を書くために調査、コードを書くことでそれぞれ異なる特性を感じることができました。

ファンタラクティブテックブログ

Discussion