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
相关产品推荐
相关产品推荐

