Skip to content

Commit 38ca7eb

Browse files
committed
[IMPL] useWebWorker hook
1 parent 88b273c commit 38ca7eb

11 files changed

Lines changed: 202 additions & 9 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useCallback, useEffect, useState } from "react";
2+
import { useWebWorker } from "../../../../../../packages/react-tools/src"
3+
4+
/**
5+
The component uses _useWebWorker_ hook to execute an heavy function in a worker to avoid burdening the main thread.
6+
*/
7+
export const UseWebWorker = () => {
8+
const [ts, setTs] = useState(Date.now());
9+
const [mess, setMess] = useState<string>("");
10+
11+
const { send } = useWebWorker({
12+
url: new URL('./worker.ts', import.meta.url),
13+
onMessage: useCallback((e: MessageEvent) => {
14+
setMess(e.data.res.join(","))
15+
}, [])
16+
});
17+
18+
useEffect(() => {
19+
const id = setInterval(() => setTs(Date.now()), 1);
20+
return () => clearInterval(id);
21+
}, []);
22+
23+
return <div>
24+
<p>Timestamp: {ts}</p>
25+
<p>Result: {mess ? mess : ""}</p>
26+
<button
27+
onClick={() => {
28+
setMess("Pending...");
29+
send("heavyTask");
30+
}}
31+
>
32+
START
33+
</button>
34+
</div>
35+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function heavyTask() {
2+
const numbers: number[] = Array(55_000_000).fill(true).map(() => Math.random() * 11)
3+
return numbers.slice(0, 5).map(el => Math.floor(el))
4+
}
5+
6+
self.onmessage = () => {
7+
const res = heavyTask();
8+
self.postMessage({ res });
9+
}

apps/react-tools-demo/src/constants/components.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ export const COMPONENTS = [
115115
"useWebSocket",
116116
"usePermission",
117117
"useMediaDevices",
118-
"useDisplayMedia"
118+
"useDisplayMedia",
119+
"useWebWorker"
119120
]
120121
],
121122
//UTILS

apps/react-tools-demo/src/markdown/useSwipe.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ useSwipe({ target, onSwipeStart, onSwipe, onSwipeEnd, options }: UseSwipeProps):
4141
object
4242
> - __param.target__: _RefObject<Element>|Element_
4343
element on which attach swipe event.
44-
> - __param.onSwipeStart?__: _(e: PointerEvent|TouchEvent) => void_
44+
> - __param.onSwipeStart?__: _(e: MouseEvent|TouchEvent) => void_
4545
callback that will be executed when swipe starts.
46-
> - __param.onSwipe?__: _(e: PointerEvent|TouchEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void_
46+
> - __param.onSwipe?__: _(e: MouseEvent|TouchEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void_
4747
callback that will be executed when swipe moves.
48-
> - __param.onSwipeEnd?__: _(e: PointerEvent|TouchEvent, direction: SwipeDirection, delta: { x: number, y: number }) => void_
48+
> - __param.onSwipeEnd?__: _(e: MouseEvent|TouchEvent, direction: SwipeDirection, delta: { x: number, y: number }) => void_
4949
callback that will be executed when swipe ends.
5050
> - __param.options?__: _Object_
5151
object to set option for listener.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# useWebWorker
2+
Hook to use [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), handling registration and communication.
3+
4+
## Usage
5+
6+
```tsx
7+
export const UseWebWorker = () => {
8+
const [ts, setTs] = useState(Date.now());
9+
const [res, setRes] = useState<number[]>([]);
10+
const [mess, setMess] = useState<string>("");
11+
12+
const { send } = useWebWorker({
13+
url: new URL('./worker.ts', import.meta.url),
14+
onMessage: useCallback((e: MessageEvent) => {
15+
setMess("");
16+
setRes(e.data)
17+
}, [])
18+
});
19+
20+
useEffect(() => {
21+
const id = setInterval(() => setTs(Date.now()), 1);
22+
return () => clearInterval(id);
23+
}, []);
24+
25+
return <div>
26+
<p>Timestamp: {ts}</p>
27+
<p>Result: {mess ? mess : res ? res.toString() : ""}</p>
28+
<button
29+
onClick={() => {
30+
setMess("Pending...");
31+
send("heavyTask");
32+
}}
33+
>
34+
START
35+
</button>
36+
</div>
37+
}
38+
```
39+
40+
> The component uses _useWebWorker_ hook to execute an heavy function in a worker to avoid burdening the main thread.
41+
42+
43+
## API
44+
45+
```tsx
46+
useWebWorker({ url, options, onMessage, onError, onMessageError }: UseWebWorkerProps): UseWebWorkerResult
47+
```
48+
49+
> ### Params
50+
>
51+
> - __param__: _UseWebWorkerProps_
52+
object
53+
> - __param.url?__: _string|URL_
54+
A string representing the URL of the script the worker will execute. It must obey the same-origin policy.
55+
> - __param.options?__: _WorkerOptions_
56+
An object containing option properties that can be set when creating the object instance.
57+
> - __param.onMessage?__: _(e: MessageEvent)=>void_
58+
function that will be executed when a message occurred.
59+
> - __param.onMessageError?__: _(e: MessageEvent)=>void_
60+
function that will be executed when a messageError occurred.
61+
> - __param.onError?__: _(e: Event)=>void_
62+
function that will be executed when an error occurred.
63+
>
64+
65+
> ### Returns
66+
>
67+
> __result__: _UseWebWorkerResult_
68+
> Object with these properties:
69+
> - __send__: function to send a message to worker.
70+
> - __terminate__: function to terminate worker.
71+
>

packages/react-tools/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
- [x] usePermission
120120
- [x] useMediaDevices
121121
- [x] useDisplayMedia
122-
- [ ] useWebWorker (https://vueuse.org/core/useWebWorker/)
122+
- [x] useWebWorker
123123
- [ ] useWebWorkerFn (https://vueuse.org/core/useWebWorkerFn/)
124124
- [ ] useIndexedDB
125125
- [ ] useFetch (with suspense ???)

packages/react-tools/src/hooks/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,5 @@ export { useContextMenu } from './useContextMenu';
9696
export { useMediaDevices } from './useMediaDevices';
9797
export { usePermission } from './usePermission';
9898
export { useDisplayMedia } from './useDisplayMedia';
99-
export { useSwipe } from './useSwipe';
99+
export { useSwipe } from './useSwipe';
100+
export { useWebWorker } from './useWebWorker';
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { useCallback, useRef } from "react"
2+
import { UseWebWorkerProps, UseWebWorkerResult } from "../models";
3+
4+
/**
5+
* **`useWebWorker`**: Hook to use [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), handling registration and communication.
6+
* @param {UseWebWorkerProps} param - object
7+
* @param {string|URL} [param.url] - A string representing the URL of the script the worker will execute. It must obey the same-origin policy.
8+
* @param {WorkerOptions} [param.options] - An object containing option properties that can be set when creating the object instance.
9+
* @param {(e: MessageEvent)=>void} [param.onMessage] - function that will be executed when a message occurred.
10+
* @param {(e: MessageEvent)=>void} [param.onMessageError] - function that will be executed when a messageError occurred.
11+
* @param {(e: Event)=>void} [param.onError] - function that will be executed when an error occurred.
12+
* @returns {UseWebWorkerResult} result
13+
* Object with these properties:
14+
* - __send__: function to send a message to worker.
15+
* - __terminate__: function to terminate worker.
16+
*/
17+
export const useWebWorker = ({ url, options, onMessage, onError, onMessageError }: UseWebWorkerProps): UseWebWorkerResult => {
18+
const worker = useRef<Worker>();
19+
const terminated = useRef(false);
20+
21+
if (!worker.current && !terminated.current) {
22+
const path = url instanceof URL ? url : new URL(url, import.meta.url);
23+
worker.current = new Worker(path, options);
24+
worker.current.onerror = (e: Event) => {
25+
!!onError && onError(e);
26+
}
27+
worker.current.onmessageerror = (e: MessageEvent) => {
28+
!!onMessageError && onMessageError(e);
29+
}
30+
worker.current.onmessage = (e: MessageEvent) => {
31+
!!onMessage && onMessage(e);
32+
}
33+
}
34+
35+
const send: UseWebWorkerResult["send"] = useCallback(<T>(message: T, transfer?: Transferable[] | StructuredSerializeOptions) => {
36+
if (Array.isArray(transfer)) {
37+
worker.current?.postMessage(message, transfer);
38+
} else {
39+
worker.current?.postMessage(message, transfer);
40+
}
41+
}, []);
42+
43+
const terminate = useCallback(() => {
44+
worker.current?.terminate();
45+
terminated.current = true;
46+
worker.current = undefined;
47+
}, []);
48+
49+
return {
50+
send,
51+
terminate
52+
}
53+
}

packages/react-tools/src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ export type {
7777
CaptureController,
7878
SwipeDirection,
7979
UseSwipeProps,
80-
UseSwipeResult
80+
UseSwipeResult,
81+
UseWebWorkerProps,
82+
UseWebWorkerResult
8183
} from './models'
8284

8385
export {
@@ -179,7 +181,8 @@ export {
179181
useMediaDevices,
180182
usePermission,
181183
useDisplayMedia,
182-
useSwipe
184+
useSwipe,
185+
useWebWorker
183186
} from './hooks'
184187

185188
export {

packages/react-tools/src/models/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ export type { UseEventSourceProps, UseEventSourceResult } from './useEventSource
2424
export type { UseWebSocketProps, UseWebSocketResult } from './useWebSocket.model';
2525
export type { UseMediaDevicesProps, UseMediaDevicesResult, TDisplayMediaStreamOptions, CaptureController } from './useMediaDevices.model';
2626
export type { TPermissionName, UsePermissionResult, TPermissionState } from './usePermission.model';
27-
export type { SwipeDirection, UseSwipeProps, UseSwipeResult } from './useSwipe.model';
27+
export type { SwipeDirection, UseSwipeProps, UseSwipeResult } from './useSwipe.model';
28+
export type { UseWebWorkerProps, UseWebWorkerResult } from './useWebWorker.model';

0 commit comments

Comments
 (0)