⏲️
JavaScriptのWorkerをPromiseにしてみる
WorkerはJavaScriptでマルチスレッドを使うための手段になります。
JavaScriptは通常、たった1つのイベントループによりタスクが一つづつ実行されます。Workerは2つ目のイベントループを作ることができます。もちろん3つ目以降も作れます。
1つ目のイベントループではDOM操作が実行されているため、たとえばWasmを使うような重たい処理があると画面がフリーズすることがあります。そういったときにWorkerが活躍します。
とはいっても、JavaScriptに慣れているとイベントループは1つだけの方がプログラミングしやすいです。そこでWorkerをPromiseにできればfetch()
関数を使うような使用感でWorkerを使うことができるようになります。
これを行うライブラリもありますが、難しい仕組みでは無いため、コピペできるcreateWork()
関数というのを作りました。
使い方
Workerを作ってcreateWork()
関数に渡すと、データを受け取って結果をPromiseで返す関数ができます。
const work = createWork(new Worker('worker.js'))
あとは、それを実行してawait
やthen
を使って結果を待つだけです。
const result = await work(6) // 7
Workerファイル
createWork()
関数を使うには、Workerファイルを少し工夫する必要があります。
通信を行うデータはidとデータのタプルとし、idを受け取ってidを返すように書き直す必要があります。
例えばこれは、データを+ 1
するWorkerです。
globalThis.addEventListener('message', event => {
const [id, data] = event.data
const result = data + 1
globalThis.postMessage([id, result]);
})
createWork()
関数
最後に、createWork()
関数の実装です。コピペして使っていただいて問題ございません。
function createWork(worker) {
const map = new Map()
let id = 0
worker.onmessage = event => {
const [id, result] = event.data;
const resolve = map.get(id)
map.delete(id)
resolve(result)
}
return data => new Promise(resolve => {
map.set(id, resolve)
worker.postMessage([id++, data])
})
}
Discussion