You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Web Worker中onmessage内使用await及异步loadPointDataView实现问题

问题解决方案

1. 在Web Worker的onmessage回调中使用await

要在onmessage里使用await,只需把回调定义为异步函数,同时确保await依赖的变量(比如filename、copc、nodePages)处于Worker全局作用域(不要放在load函数局部)。修改后的Worker代码如下:

import { Copc, Key } from "copc";

// 把跨函数访问的变量提升到全局
var nodePages, pages, receivedData;
let filename, copc, x_min, y_min, z_min, width;

async function load() {
  filename = "https://s3.amazonaws.com/data.entwine.io/millsite.copc.laz";
  copc = await Copc.create(filename);
  const scale = copc.header.scale[0];
  [x_min, y_min, z_min, , , ] = copc.info.cube;
  const [, , , x_max, y_max, z_max] = copc.info.cube;
  width = Math.abs(x_max - x_min);
  receivedData = await Copc.loadHierarchyPage(
    filename,
    copc.info.rootHierarchyPage
  );
  nodePages = receivedData.nodes;
  pages = receivedData.pages;
  postMessage(200);
}

// 改为async回调,直接使用await
onmessage = async function (message) {
  const index = message.data;
  // 确保keyCountMap和m为Worker全局变量
  const myRoot = nodePages[keyCountMap[m]];
  const view = await Copc.loadPointDataView(filename, copc, myRoot);
  // 后续处理view的逻辑...
};

// 初始化执行load
load();

2. 在Web Worker中实现异步函数loadPointDataView

Copc.loadPointDataView本身就是异步函数,只要Worker环境能正常加载Copc库(你的import语句没问题),且传入的参数(filename、copc实例、节点对象)正确,就能直接调用。核心是保证变量作用域正确——比如上面代码把filename和copc设为全局,就能在onmessage里直接使用。

3. 并行化原有代码的实现

原有代码是串行执行节点加载和点数据读取,要并行化需做到:

  • 外层用Promise.all并行处理所有节点的loadPointDataView请求
  • 内层readPoints分块任务也用Promise.all并行执行

修改后的并行化代码(以Worker为例):

import { Copc, Key } from "copc";

let filename = "https://s3.amazonaws.com/data.entwine.io/millsite.copc.laz";
let scale, nodePages, pages;
let x_min, y_min, z_min, width;
const positions = [];
const colors = [];
// 假设color为已定义的Color实例(如Three.js的Color)
const color = new Color();

async function init() {
  const copc = await Copc.create(filename);
  scale = copc.header.scale[0];
  [x_min, y_min, z_min, , , ] = copc.info.cube;
  const [, , , x_max, y_max, z_max] = copc.info.cube;
  width = Math.abs(x_max - x_min);
  const result = await Copc.loadHierarchyPage(
    filename,
    copc.info.rootHierarchyPage
  );
  nodePages = result.nodes;
  pages = result.pages;

  // 并行处理所有节点任务
  await parallelProcessNodes(copc);
  
  // 处理完成后将结果发送回主线程
  postMessage({ positions, colors });
}

async function parallelProcessNodes(copc) {
  // 生成所有节点的处理Promise
  const nodePromises = [];
  for (let m = 0; m < keyCountMap.length; m += 2) {
    const promise = (async () => {
      const myRoot = nodePages[keyCountMap[m]];
      const view = await Copc.loadPointDataView(filename, copc, myRoot);
      const getters = ["X", "Y", "Z", "Intensity"].map(view.getter);
      const chunkCount = 20;
      const innerPromises = [];

      // 并行处理分块的readPoints
      for (let j = 0; j < keyCountMap[m + 1]; j += chunkCount) {
        innerPromises.push(readPoints(j, getters));
      }
      await Promise.all(innerPromises);
    })();
    nodePromises.push(promise);
  }
  // 等待所有节点任务完成
  await Promise.all(nodePromises);
}

async function readPoints(id, getters) {
  const returnPoint = getXyzi(id, getters);
  positions.push(
    returnPoint[0] - x_min - 0.5 * width,
    returnPoint[1] - y_min - 0.5 * width,
    returnPoint[2] - z_min - 0.5 * width
  );
  const vx = (returnPoint[3] / 65535) * 255;
  color.setRGB(vx, vx, vx);
  colors.push(color.r, color.g, color.b);
  // 无异步操作时可直接resolve,后续有异步逻辑再保留Promise结构
  return Promise.resolve();
}

function getXyzi(index, getters) {
  return getters.map((get) => get(index));
}

// 初始化执行
init();

关键优化点:

  • 外层循环用Promise.all并行加载多个节点的PointDataView,避免串行等待
  • 内层分块读取点数据时,用Promise.all并行处理,提升读取效率
  • 每个节点的处理逻辑包装为独立异步函数,确保并行执行互不阻塞

内容的提问来源于stack exchange,提问作者Pravin Poudel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 12:05:44