git.iko.soy/rowtype-yoga/purescript-web-proletarian
on main help sign in
feat: add disposable worker subscriptions and failure hooks
369ed37Mark
README.md+2−2
@@ -24,7 +24,7 @@ import Yoga.WebProletarian.Types (Worker)
24import Yoga.WebWorker (postMessageToBoss, subscribe)
24import Yoga.WebWorker (postMessageToBoss, subscribe)
25
25
26main ∷ Effect Unit
26main ∷ Effect Unit
27−main = subscribe (\(i :: Int) -> postMessageToBoss (show i))
27+main = void $ subscribe (\(i :: Int) -> postMessageToBoss (show i))
28
28
29foreign import newWorker ∷ Effect (Worker Int String)
29foreign import newWorker ∷ Effect (Worker Int String)
30```
30```
@@ -66,7 +66,7 @@ import Worker.Echo as Echo
66main :: Effect Unit
66main :: Effect Unit
67main = do
67main = do
68 worker ← Echo.newWorker
68 worker ← Echo.newWorker
69− worker # onMessageFromWorker \msg -> do
69+ void $ worker # onMessageFromWorker \msg -> do
70 Console.log msg
70 Console.log msg
71 worker # terminate
71 worker # terminate
72 worker # postMessageToWorker 42
72 worker # postMessageToWorker 42
src/Yoga/WebBoss.js+13−4
@@ -1,10 +1,19 @@
1export const onMessageFromWorker = handler => worker => () => {
1export const onMessageFromWorker = handler => worker => () => {
2− worker.onmessage = (msg => handler(msg.data)())
2+ const listener = event => handler(event.data)();
3+ worker.addEventListener("message", listener);
4+ return () => worker.removeEventListener("message", listener);
3−}
5+};
4
6
5export const onErrorFromWorker = handler => worker => () => {
7export const onErrorFromWorker = handler => worker => () => {
8+ const listener = event => handler(event)();
6− worker.addEventListener("error", e => handler(e.message)())
9+ worker.addEventListener("error", listener);
10+ return () => worker.removeEventListener("error", listener);
11+};
12+
13+export const onMessageErrorFromWorker = handler => worker => () => {
14+ worker.addEventListener("messageerror", handler);
15+ return () => worker.removeEventListener("messageerror", handler);
7−}
16+};
8
17
9export const postMessageToWorker = msg => worker => () => worker.postMessage(msg)
18export const postMessageToWorker = msg => worker => () => worker.postMessage(msg)
10
19
src/Yoga/WebBoss.purs+6−2
@@ -3,14 +3,18 @@ module Yoga.WebBoss where
3import Prelude
3import Prelude
4
4
5import Effect (Effect)
5import Effect (Effect)
6+import Web.HTML.Event.ErrorEvent (ErrorEvent)
6import Yoga.WebProletarian.Transferable (Transferable)
7import Yoga.WebProletarian.Transferable (Transferable)
7import Yoga.WebProletarian.Types (Worker)
8import Yoga.WebProletarian.Types (Worker)
8
9
9foreign import onMessageFromWorker
10foreign import onMessageFromWorker
10− ∷ ∀ toWorker toBoss. (toBoss → Effect Unit) → Worker toWorker toBoss → Effect Unit
11+ ∷ ∀ toWorker toBoss. (toBoss → Effect Unit) → Worker toWorker toBoss → Effect (Effect Unit)
11
12
12foreign import onErrorFromWorker
13foreign import onErrorFromWorker
13− ∷ ∀ toWorker toBoss. (String → Effect Unit) → Worker toWorker toBoss → Effect Unit
14+ ∷ ∀ toWorker toBoss. (ErrorEvent → Effect Unit) → Worker toWorker toBoss → Effect (Effect Unit)
15+
16+foreign import onMessageErrorFromWorker
17+ ∷ ∀ toWorker toBoss. Effect Unit → Worker toWorker toBoss → Effect (Effect Unit)
14
18
15foreign import postMessageToWorker ∷ ∀ toBoss toWorker. toWorker → Worker toWorker toBoss → Effect Unit
19foreign import postMessageToWorker ∷ ∀ toBoss toWorker. toWorker → Worker toWorker toBoss → Effect Unit
16
20
src/Yoga/WebWorker.js+22−4
@@ -1,10 +1,28 @@
1export const subscribe = handler => () => {
1export const subscribe = handler => () => {
2− addEventListener("message", (event) => {
3− handler(event.data)();
2+ const listener = event => handler(event.data)();
4− })
3+ addEventListener("message", listener);
4+ return () => removeEventListener("message", listener);
5−}
5+};
6
6
7export const quit = () => close()
7export const quit = () => close()
8
8
9export const postMessageToBoss = data => () => postMessage(data)
9export const postMessageToBoss = data => () => postMessage(data)
10
10
11+export const onFailure = handler => () => {
12+ const onError = event => {
13+ event.preventDefault();
14+ handler(event.message || "Worker execution failed")();
15+ };
16+ const onRejection = event => {
17+ event.preventDefault();
18+ const reason = event.reason;
19+ handler(reason instanceof Error ? reason.message : String(reason))();
20+ };
21+ addEventListener("error", onError);
22+ addEventListener("unhandledrejection", onRejection);
23+ return () => {
24+ removeEventListener("error", onError);
25+ removeEventListener("unhandledrejection", onRejection);
26+ };
27+};
28+
src/Yoga/WebWorker.purs+5−1
@@ -3,9 +3,13 @@ module Yoga.WebWorker where
3import Prelude
3import Prelude
4import Effect (Effect)
4import Effect (Effect)
5
5
6−foreign import subscribe :: forall toWorker. (toWorker -> Effect Unit) -> Effect Unit
6+foreign import subscribe :: forall toWorker. (toWorker -> Effect Unit) -> Effect (Effect Unit)
7
7
8foreign import quit :: Effect Unit
8foreign import quit :: Effect Unit
9
9
10foreign import postMessageToBoss :: forall toBoss. toBoss -> Effect Unit
10foreign import postMessageToBoss :: forall toBoss. toBoss -> Effect Unit
11
11
12+-- | Handle worker-global exceptions and rejected promises. Installing this
13+-- | handler consumes their default reporting; disposing restores it.
14+foreign import onFailure :: (String -> Effect Unit) -> Effect (Effect Unit)
15+