mirror of
https://github.com/muerwre/muerwre.github.io.git
synced 2025-04-25 02:46:39 +07:00
68 lines
No EOL
2 KiB
Markdown
68 lines
No EOL
2 KiB
Markdown
Rendering items on #canvas in main loop ==might cause interface freezes==, preventing render process from executing properly by flooding execution stack with operations.
|
|
|
|
To handle it properly, we can start separate #worker thread, that will handle rendering in its own event loop, so that won't affect the source tab's event loop.
|
|
|
|
Workers can have access to [Transferrable Objects](https://developer.mozilla.org/en-US/docs/Glossary/Transferable_objects) from main thread by receiving memory address. ==That's a lot faster than cloning==. In this case [ImageBitmap](https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap) is transferrable.
|
|
|
|
Code for the main thread component:
|
|
|
|
```typescript
|
|
// main.ts
|
|
const instance = new Worker('./render-worker.ts');
|
|
const canvas = document.getElementById('view');
|
|
|
|
// attaching event listener to worker
|
|
instance.onmessage = (event: MessageEvent) => {
|
|
const ctx = canvas?.getContext("2d");
|
|
if (!ctx) {
|
|
throw new Error(`Can't get 2D context`);
|
|
}
|
|
|
|
ctx.drawImage(event.data as ImageBitmap, 0, 0);
|
|
}
|
|
|
|
// sending canvas contents to worker
|
|
const renderInCanvas = () => {
|
|
if (!canvas.current) {
|
|
return;
|
|
}
|
|
|
|
createImageBitmap(canvas.current).then(image => {
|
|
instance.postMessage(image, { transfer: [image] })
|
|
});
|
|
};
|
|
```
|
|
|
|
Worker code:
|
|
|
|
```typescript
|
|
// render-worker.ts
|
|
export default () => {
|
|
self.onmessage = (message: MessageEvent) => {
|
|
const data = message.data;
|
|
|
|
if (!(data instanceof ImageBitmap)) {
|
|
throw new Error('Received unknown data')
|
|
}
|
|
|
|
// OffscreenCanvas can be set up inside workers
|
|
const canvas = new OffscreenCanvas(data.width, data.height);
|
|
const ctx = canvas.getContext("2d");
|
|
|
|
if (!ctx) {
|
|
throw new Error(`Can't get 2D context`);
|
|
}
|
|
|
|
ctx.drawImage(data, 0, 0);
|
|
|
|
// That will block execution inside worker for
|
|
// a couple of seconds
|
|
doHardRenderingStuffHere(ctx, data.width, data.height);
|
|
|
|
// Sending resulting image back to main thread
|
|
createImageBitmap(canvas).then((image) => {
|
|
self.postMessage(image, { transfer: [image] });
|
|
});
|
|
};
|
|
};
|
|
``` |