This clojurescript library wraps the web worker api and provides an simple way for multithreading within browsers with cljs.
Add the following dependency to your project.cljs
:
To understand web workers itself see the web worker api. Or see the quick guide.
The following example handling both the browser and the worker within one script. The script provides an worker mirroring its inputs as outputs and testing four worker calls. Two of them will success and two of them will fail.
(ns cljs-workers.test
(:require [cljs.core.async :refer [<!]]
[cljs-workers.core :as main]
[cljs-workers.worker :as worker])
(:require-macros [cljs.core.async.macros :refer [go]]))
;; Setup the browser path (handling both in one file)
(defn app
[]
(let [;; you can create one worker or a pool (async channel of workers)
worker-pool
(main/create-pool 2 "worker.js")
;; a "do-with-pool" or "-worker" (see below) will return immediately and give you a result channel. So to print the result you have to handle the channel
print-result
(fn [message result-chan]
(go
(let [result (<! result-chan)]
(.debug js/console
message
(str (:state result))
(clj->js result)))))]
(print-result "Copy all simple values" (main/do-with-pool! worker-pool {:handler :mirror, :arguments {:a "Hallo" :b "Welt" :c 10}}))
(print-result "Copy the simple values and transfer the ArrayBuffer" (main/do-with-pool! worker-pool {:handler :mirror, :arguments {:a "Hallo" :b "Welt" :c 10 :d (js/ArrayBuffer. 10) :transfer [:d]} :transfer [:d]}))
(print-result "Copy the simple values and transfer the ArrayBuffer, but transfer (browser thread) will fail cause the wrong value and the wrong type is marked to do so" (main/do-with-pool! worker-pool {:handler :mirror, :arguments {:a "Hallo" :b "Welt" :c 10 :d (js/ArrayBuffer. 10) :transfer [:d]} :transfer [:c]}))
(print-result "Copy the simple values and transfer the ArrayBuffer, but transfer mirroring (worker thread) will fail cause the wrong value and the wrong type is marked to do so" (main/do-with-pool! worker-pool {:handler :mirror, :arguments {:a "Hallo" :b "Welt" :c 10 :d (js/ArrayBuffer. 10) :transfer [:c]} :transfer [:d]}))
(print-result "Copy values but do it with every worker of the pool" (main/do-for-pool! worker-pool {:handler :mirror, :arguments {:a "Hallo" :b "Welt" :c 10}}))))
;; Setup the worker path (handling both in one file)
(defn worker
[]
(worker/register
:mirror
(fn [arguments]
arguments))
(worker/bootstrap))
;; Decide which path to setup
(if (main/main?)
(app)
(worker))
Workers have their own context, not the global window context. So there is no document / DOM and some other things are also not present.
To handle data between these two contexts you have to copy or transfer your values / objects. Consider, you can copy values / objects handled by the structured clone algorithm and transfer transferables, everything else will cause an error. But don´t be worried, most the time that´s no problem.
Since there are two contexts, you have to provide two script threads / procedures. You can handle this by providing two script files or you can also provide one file handling both. When using the second way pay attention on what you get with the current context (workers have no DOM).
For full documentation see the web worker api.
I´d be thankful to receive patches, comments and constructive criticism.
Hope the package is useful :-)