【问题标题】:Send offscreencanvas to webworker more than once不止一次向 webworker 发送 offscreencanvas
【发布时间】:2020-04-23 04:06:14
【问题描述】:

我希望能够多次将我的画布屏幕外发送给网络工作者。

这是一个示例代码:

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" />
  );
}

如果用户决定取消绘图,我们的想法是能够杀死网络工作者。 当我将消息重新发布给新的网络工作者时,我收到以下错误:

DataCloneError: Failed to execute 'postMessage' on 'Worker':
An OffscreenCanvas could not be cloned because it was detached.

【问题讨论】:

    标签: canvas web-worker offscreen-canvas


    【解决方案1】:

    您可以多次发送它,但为此,您需要将其从工作人员那里转移回来,我猜这会违背您的目的,因为工作人员需要有空闲才能处理该请求,如果是,就没有必要“杀死”它。

    因此,您可能更喜欢创建一个独立的 OffscreenCanvas,使用同名的 constructor 将留在 Worker 中并在 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>

    【讨论】:

    • 这种方法有效,除了两件事:1)用户看不到正在绘制的图像,我可以接受。 2)画布构建位图需要很长时间(例如,此命令“transferToImageBitmap”)。当我在画布上画完像素后,我的印象是,画布已经准备好进行可视化了。我看到完成上下文绘制和浏览器中的实际渲染之间存在很大的滞后时间。
    • “用户看不到正在绘制的图像”这是什么意思?对于“长时间”的事情,您是否删除了 while ( Date.now() - start &lt; 5000 ) { } 行?
    • 1.使用我的原始代码,在绘制画布时,浏览器实际上会立即更新。但我很满意只看到最后更新的图像。至于长时间的延迟,我运行了我的代码,不确定。我注意到当我在画布上画很多线时,transferToImageBitmap 命令需要永远返回。
    • 什么代码?使用您提供的代码,不会绘制任何内容。
    • 这只是渲染代码。这个想法是当向工作人员发布 transferControlToOffscreen 时,它会直接在主浏览器中绘制到画布上。
    猜你喜欢
    • 2019-10-26
    • 2014-07-27
    • 2018-05-24
    • 2016-02-02
    • 1970-01-01
    • 1970-01-01
    • 2014-08-16
    • 2017-07-19
    • 1970-01-01
    相关资源
    最近更新 更多