问题
I want to be able to send my canvas offscreen to a webworker more than once.
Here's an example code:
render() {
const worker = new Worker("some url");
const offscreen = this.canvasRef.current.transferControlToOffscreen();
this.worker.postMessage({
offscreen
}, [offscreen]);
return (
<canvas ref={this.canvasRef} height="800" width="1000" />
);
}
The idea is to be able to kill the web worker if user decides to cancel the drawing. Put when I repost the message to a new web worker, I get the following error:
DataCloneError: Failed to execute 'postMessage' on 'Worker':
An OffscreenCanvas could not be cloned because it was detached.
回答1:
You could send it more than once, but for this, you'd need to transfer it back from the worker, which kind of defeats your purpose I guess since the worker would need to be free to be able to handle that request, and if it is, there is no need to "kill" it.
So instead, you may prefer to create a standalone OffscreenCanvas, using the eponymous constructor that will stay in the Worker and to draw it on a BitmapRenderingContext:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('bitmaprenderer');
const stop_btn = document.getElementById('stop_btn');
document.getElementById('start_btn').onclick = e => {
console.log( 'starting a new drawing' );
const worker = new Worker(getWorkerURL());
worker.onmessage = e => {
console.log('drawing complete');
// pass it to the visible canvas
ctx.transferFromImageBitmap(e.data);
start_btn.disabled = false;
stop_btn.disabled = true;
};
stop_btn.onclick = e => {
console.log('drawing canceled');
worker.terminate();
start_btn.disabled = false;
stop_btn.disabled = true;
};
start_btn.disabled = true;
stop_btn.disabled = false;
};
function getWorkerURL() {
const el = document.getElementById('worker_script');
const blob = new Blob([el.textContent]);
return URL.createObjectURL(blob);
}
<button id="start_btn">start</button>
<button id="stop_btn">stop</button><br>
<canvas id="canvas" width="500" height="500"></canvas>
<script id="worker_script" type="ws">
const canvas = new OffscreenCanvas(500, 500);
const gl = canvas.getContext('webgl');
gl.viewport(0, 0,
gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.enable(gl.SCISSOR_TEST);
// make some slow noise (we're in a Worker)
for(let y=0; y<gl.drawingBufferHeight; y++) {
for(let x=0; x<gl.drawingBufferWidth; x++) {
gl.scissor(x, y, 1, 1);
gl.clearColor(Math.random(), Math.random(), Math.random(), 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
}
}
// make it last a bit longer than really needed
const start = Date.now();
while ( Date.now() - start < 5000 ) { }
const img = canvas.transferToImageBitmap();
postMessage(img, [img]);
</script>
来源:https://stackoverflow.com/questions/59598111/send-offscreencanvas-to-webworker-more-than-once