Fmlib_js.Web_workerCreate webworker in the main thread and in the worker thread.
An application using webworker has two parts:
The creator and the worker can communicate only by sending messages. Usually in javascript a webworker is created by
function callback (msg) {
// actions on receiving messages from the worker
}
var worker = new Worker('url_to_worker.js')
worker.onmessage = callback
worker.postMessage (...) // send a message to the workerThen there is a javascript implementation of the worker.
function onmessage (msg) {
// actions on receiving a message from the creator
...
postMessage (...) // send a message to the creator
}
... // initialization code
postMessage (...) // optional initial message to the creator
...Both parts the creator part and the implementation part can be implemented in ocaml and this module provides functions to support that.
The call
let worker = Web_worker.start "url" decode callbackstarts a worker whose implementation can be found at "url". decode is a decoder to decode messages from the webworker and the function callback processes the decoded messages.
decode: 'msg Decode.t
callback: 'msg -> unitIf the message received from the webworker cannot be decoded, the event will be logged via console.log.
The webworker has a function post to send messages to the worker. I.e. at any time you can call
Web_worker.post msg workerwhere msg is an arbitrary javascript value i.e. msg: Value.t.
The command
Web_worker.terminate workerterminates the worker.
Warning: If the html where the code of the creator resides has been loaded into the browser with an url like file://...., and the url of the command Webworker.start url decode callback is relative, then the browser cannot load the worker. The worker code must always be loaded from a server (which can be a local server).
In ocaml the implementation of a web worker has two components:
decode to decode messages which are received as javascript values into ocaml values. let worker (post: Value.t -> unit): 'msg -> unit =
... (* initialization code *)
...
fun msg ->
... (* code executed on receiving a decoded message of type
['msg] *)
...Having the decoder and the worker function, the actual webworker is made by the command
make decode workerThe make function retrieves the javascript function postMessage which must be available in the implementation environment of a webworker and decodes all incoming messages from the creator. make calls worker in a curried form. First to provide it with the retrieve function postMessage and subsequently on each decoded incoming message.
If a message from the creator cannot be decoded, then the event is logged in the console.
Type of a web worker in the creator which can receive messages of type 'msg from the actual worker.
val start : string -> 'msg Base.Decode.t -> ('msg -> unit) -> tstart url decode callback
Create a webworker loaded from url and register the callback callback to receive messages from the webworker. Use the decoder decode to decode messages received from the webworker.
val post_message : Base.Value.t -> t -> unitpost msg w Post the message msg to the worker w.
val terminate : t -> unitterminate worker Terminate the webworker worker.
type 'msg worker_function = (Base.Value.t -> unit) -> 'msg -> unitType of a worker function.
A worker function f of that type is called in a curried form. In the first call, it receives a function to post messages to its creator.
let g = f postIn subsequent calls, it receives messages from its creator
g msgval make : 'msg Base.Decode.t -> 'msg worker_function -> unitmake decode f
Make the actual webworker. decode is a decoder for incoming messages. f is the main function of the worker. f is called in a curried form. The first call is
let g = f postwhere post is the function to send messages back to the creator of the worker.
Then each time a message is received from the creator of the webworker, the message is decoded by decode. In case of success with the ocaml object msg the function call g msg is made.
The function make might raise 2 possible exceptions:
postMessage i.e. it does not run in a webworker environment.postMessage but the object is not a function. This indicates as well that it is not executed in a webworker environment.If during the execution of the worker messages arrive which cannot be decoded successfully by decode, then this event is logged.
Sometimes it is useful to simulated the behaviour of a webworker in the main thread. As opposed to a real webworker, a simulator runs in the main thread and therefore can block the event loop for a certain amount of time.
Recall that a real webworker is started in the main thread by
let worker = Web_worker.start "url" decode callbackwhere decode is a decoder for messages received from the worker and callback is a function which is called on each received message from the worker.
The behaviour of a worker is completely described by the pair (dec,wfun) where dec is a decoder for messages received from the creator and wfun is a workerfunction.
The simulator is started from the main thread by
let worker = Web_worker.Simulate.start decode callback dec funand there are the functions
Web_worker.Simulate.post_message msg worker
Web_worker.Simulate.terminate workerto send messages to the worker and to terminate the worker.
module Simulate : sig ... endSimulate the behaviour of a webworker in the main thread.
It is also possible to simulate the behaviour of a web worker written in ocaml within javascript code. Let's assume that the webworker is defined by the pair (decode, wfun). Then we write an ocaml file with the content
let decode = ...
let wfun = ...
let _ =
Web_worker.Simulate.simulate_js "Simulated_worker" decode wfunand compile it to worker.js. Then instead of writing a html file
<html>
<body>
...
<script>
var worker = new Worker("worker.js")
worker.onmessage = (msg) => {...}
worker.postMessage (msg)
</script>
</body>
</html>we write the html file
<html>
<head>
<script type="text/javascript" src="worker.js"></script>
</head>
<body>
...
<script>
var worker = Simulated_worker ((msg) => ... )
worker.postMessage (msg)
</script>
</body>
</html>val simulate_js : string -> 'msg Base.Decode.t -> 'msg worker_function -> unitsimulate_js name decode wfun
Create a simulation of a webworker given by (decode, wfun) and make it accessible from the javascript code under the name name.
In javascript you write var worker = name (callback) to start the worker and worker.postMessage(msg) to send a message to the worker. Furthermore it is possible to terminate the worker by worker.terminate().