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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 22:15:00