JavaScript操作COM串口读写完成后如何正确关闭端口?
问题根源
你遇到的done分支不触发是Web Serial API的正常表现:reader.read()返回的done为true的唯一前提是串口输入流被主动关闭,硬件完成数据传输后不会主动断开流,所以你的代码会永远卡在等待读取的状态,永远进不了done分支。
优化&解决思路
你已经明确知道合法数据的分割规则(分号分割,总段数为169/173),完全不需要用setTimeout等待1秒再读,也不用等done信号,收到符合长度的完整数据后主动终止读取、关闭串口即可,逻辑如下:
- 发送指令后直接启动读取,不用延迟1秒
- 拼接数据校验符合长度要求后,主动取消读取器锁定、关闭串口
- 修复代码里的笔误:你把拼接好的
hardwareData写成了未定义的et2Daten - 串口关闭后下次调用
readData会重新触发用户选串口流程,直接复用方法即可
修正后的可运行代码
if ("serial" in navigator) { let hardwareData = ''; // 建议显式声明变量,不要用全局隐式声明 readData(); async function readData() { console.log('read'); let port; let reader; try { // 提示用户选择串口 port = await navigator.serial.requestPort(); // 等待串口打开,传入硬件参数 await port.open({ baudRate: 115200, dataBits: 8, stopBits: 1, parity: "none" }); // 向硬件发送"X"指令 const encoder = new TextEncoder(); const writer = port.writable.getWriter(); await writer.write(encoder.encode("X")); writer.releaseLock(); // 直接启动读取,不需要延迟1秒 while (port.readable) { reader = port.readable.getReader(); try { while (true) { const { value, done } = await reader.read(); if (done) break; if (value) { hardwareData += new TextDecoder().decode(value); hardwareData = hardwareData.replace(/\s/g, ''); const res = hardwareData.split(";"); // 修复原代码的变量笔误 const anzahl = res.length; // 收到符合长度的完整数据 if (anzahl == 173 || anzahl == 169) { console.log("Anzahl: " + anzahl); // 上传数据 $.ajax({ url: APPLICATION_PATH + 'Home/ReadDataFromET2', type: 'POST', dataType: 'json', data: JSON.stringify({ 'data': hardwareData, }), contentType: "application/json; charset=utf-8", success: function (data) { console.log(data); }, error: function (request) { console.error('上传失败', request); } }); // 主动终止读取 reader.cancel(); break; } } } } catch (error) { console.error("读取错误", error); } finally { // 释放读取器锁定 reader?.releaseLock(); } // 收到完整数据,跳出读取循环 break; } } catch (err) { console.error('串口操作失败', err); } finally { // 确保串口一定被关闭 if (port) { await port.close(); console.log('串口已关闭,可再次调用readData复用'); // 重置数据缓存 hardwareData = ''; } } } }
补充说明
如果你的硬件可能出现传输不完整的情况,可以加个超时兜底:超过2秒还没收到符合长度的数据,就主动关串口抛出超时错误,避免串口一直被占用。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

