React Worker Pool Context Component
Reuse workers and management flexible, make browser main thread happily to render and feeling smooth.
** in developing feth Not the npm module, just the component in create-react-app now. **
GIF
Experiment
目前為學習研究與實驗性質,請勿使用在正式環境中。
This project is in experiment, dont's use it on production environment.
Why
Make browser main thread happily to render and feeling smooth.
The React is always sync now, if we have some cpu heavy computing, it will affect the main thread render, and the browser looks like delay we call frame drop, we can use browser native Worker API to handle the cpu heavy computing to cost down the CPU.
Graph
(block)
- React Main Thread
- heavy computing thing
- React render reconciler(block and going) - 4ms
- heavy computing thing run(block and going) - 18ms
- broswer repaint/reflow(block and going)
- heavy computing thing
- React render reconciler(block and going) - 5ms
- heavy computing thing run(block and going) - 16ms
- broswer repaint/reflow(block and going)
(non-block)
- React Main Thread
- heavy computing thing
- call worker -------------->(thread non-block) - 1ms
- React render reconciler-----------|(block and going) - 2ms
- broswer repaint/reflow------------|(block and going)
- worker done ------------->(thread non-block) - 1ms
- React render reconciler-----------|(block and going) - 3ms
- broswer repaint/reflow------------|(block and going)
Core
Only ./src/ReactWorkerPool/index.tsx
Public API
- requestWorker(name: string; code: string; timeout?: number): (name: string)
- releaseWorker(name: string): boolean
- run(name: string; ...args: any): void;
- getResult: Promise<any>
Used
The WorkerPool is base on React Context API so we import it and use it on top of other components which components want to use worker.
import WorkerPool from "./ReactWorkerPool";
ReactDOM.render(
<React.StrictMode>
<WorkerPool>
<App />
</WorkerPool>
</React.StrictMode>,
document.getElementById("root")
);
When we completed the Provider setup, and than go to the child component to useContext.
import { WorkerPoolContext } from "./ReactWorkerPool";
const workerPool = useContext(WorkerPoolContext);
The WorkerPool is big pool, it maintain all the worker, we will request the first Worker instance from useEffect.
useEffect(() => {
const code = `self.onmessage = (e) => {
const [num1, num2] = e.data
let sum = 0
for (let i = num1; i < num2; i++) {
sum += i
}
self.postMessage(sum)
}`;
workerPool.requestWorker("count", code);
workerPool.requestWorker("echo", echo);
}, [code, echo, workerPool]);
Last, we can call worker anywhere.
const clickToCount = async () => {
workerPool.run("count", [num1, num2]);
const data = await workerPool.getResult("count");
if (data) {
setSum(data);
}
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<button onClick={clickToCount}>Click To Count From Child Thread</button>
<div className="App-link">The total is: {sum}</div>
</header>
</div>
);
Reference
License
MIT