如何从Web Worker打开WebSerialAPI选中的SerialPort?
解决Web Serial API中无法将SerialPort传递给Web Worker的问题
方案1:使用SerialPort.for()传递权限令牌(推荐)
这是Web Serial API官方支持的跨上下文传递端口的方法,通过生成可序列化的权限令牌,让Worker获取对应的端口实例:
主线程代码:
// 主线程:用户选择串口后生成权限令牌并发送给Worker let port = await navigator.serial.requestPort(); // 请求用于指定Worker的端口权限令牌 const portToken = await port.for(serialportWorker); // 将令牌发送给Worker serialportWorker.postMessage({ type: "open-port", token: portToken });
Web Worker代码:
// Web Worker:通过令牌获取端口并处理串口流 self.onmessage = async (event) => { if (event.data.type === "open-port") { try { // 用令牌获取对应的SerialPort实例 const port = await navigator.serial.getPort(event.data.token); if (!port) { console.error("无法通过令牌获取指定串口"); return; } // 打开串口(根据你的设备配置波特率等参数) await port.open({ baudRate: 9600 }); // 开始读取串口数据 const reader = port.readable.getReader(); while (true) { const { value, done } = await reader.read(); if (done) { reader.releaseLock(); break; } // 处理数据,可将结果发回主线程 self.postMessage({ type: "serial-data", data: value }); } } catch (err) { console.error("串口操作出错:", err); } } };
原理:SerialPort.for()方法会生成一个可被结构化克隆的令牌,Worker通过navigator.serial.getPort()传入令牌即可获取对应的端口实例,完全避免了直接传递无法克隆的SerialPort对象的问题。
方案2:主线程转发串口数据到Worker(兼容 fallback)
如果目标浏览器不支持SerialPort.for()方法,可以让主线程仅负责打开串口和转发原始数据,将数据处理逻辑放在Worker中,最小化主线程的工作量:
主线程代码:
// 主线程:打开串口并转发数据到Worker let port = await navigator.serial.requestPort(); await port.open({ baudRate: 9600 }); const reader = port.readable.getReader(); // 持续读取串口数据并转发给Worker (async function forwardSerialData() { while (true) { const { value, done } = await reader.read(); if (done) { reader.releaseLock(); break; } // 仅转发原始数据,不做复杂处理 serialportWorker.postMessage({ type: "raw-data", data: value }, [value.buffer]); // 用Transferable Objects优化数据传递性能 } })();
Web Worker代码:
// Web Worker:处理串口数据 self.onmessage = (event) => { if (event.data.type === "raw-data") { // 在这里处理高吞吐量的串口数据,不会阻塞主线程 const processedData = handleSerialData(event.data.data); // 可选:将处理结果发回主线程 self.postMessage({ type: "processed-data", result: processedData }); } }; function handleSerialData(rawData) { // 实现你的数据解析逻辑,比如GPS数据解析 // ... }
注意:使用Transferable Objects(代码中的[value.buffer])可以避免数据拷贝,提升大吞吐量数据的传递性能。
内容的提问来源于stack exchange,提问作者Patryk
相关产品推荐
相关产品推荐

