Javascript如何与硬件设备交互?

来源:DB2教程作者:风铃头衔:草根站长
导读:本期聚焦于风铃创作的《Javascript如何与硬件设备交互?》,敬请观看详情。浏览器里的JavaScript一度被认为只能操作DOM与网络请求,但在硬件交互场景中它已经能直接读写串口、USB设备和蓝牙外设。Web Serial API让网页在用户授权后获得串口访问能力,能向Arduino、ESP32等开发板发送指令并接收传感器数据;WebUSB则面向实现USB特定协议的设备;WebHID适合键盘、游戏手柄等人机接口设备。本文从权限模型、核心API流程和实际读取Arduino温湿度数据三个层面说明JavaScript与硬件通信的实现方式,同时对比Node.js下serialport方案的差异,帮助开发者理清连接、读写、断开全流程,避免混用API造成权限错误。

JavaScript 与硬件设备交互的核心并不神秘:它依靠浏览器或 Node.js 暴露的底层接口,把硬件抽象成可读写的流或端点。浏览器端最常用的是 Web Serial API、WebUSB 和 WebHID,分别对应串口、USB 协议设备与人机接口设备;Node.js 端则主要使用 serialport、usb、node-hid 等原生模块。两者共同点是都需要用户授权或系统权限,并且读写操作均基于异步模型。

Javascript如何与硬件设备交互?

浏览器端:Web Serial API 的连接与读写

Web Serial API 允许网页在用户主动选择串口后获得访问权限。对 Arduino、ESP32、树莓派 Pico 这类常见开发板来说,USB 转串口芯片会把 USB 接口映射为一个串口设备,因此 Web Serial 是门槛最低的浏览器硬件入口。

连接流程开始于 navigator.serial.requestPort()。该方法必须由用户手势触发,例如点击按钮。拿到 SerialPort 对象后调用 port.open() 并传入波特率。读写通过 port.readable 和 port.writable 两个流完成,这意味着可以配合 TransformStream 或直接使用 reader 和 writer 处理数据。

// 请求串口并打开
const port = await navigator.serial.requestPort();
await port.open({ baudRate: 9600 });

// 读取数据
const reader = port.readable.getReader();
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}

写入通常使用 TextEncoder 将字符串转为 Uint8Array,再交给 writer.write()。串口数据没有消息边界,实际开发中经常按换行符或固定长度帧拆包。比如 Arduino 每秒钟发送一行 sensor:25.6,网页端可以累积 buffer 直到遇到 \n 再解析。

需要注意,Web Serial 在 iframe 中受到权限策略限制,而且只能通过 HTTPS 或 localhost 使用。关闭页面后连接会自动断开,硬件端不会保留来自浏览器的会话。

WebUSB 与 WebHID 的适用场景

WebUSB 解决的问题是:不是所有 USB 设备都呈现为串口。某些厂商自定义 USB 协议的设备在系统里没有标准驱动,传统网页无法访问它们。WebUSB 允许页面声明特定的 vendorId 和 productId,并通过 USB 控制传输、批量传输等方式与设备通信。

使用 WebUSB 前建议先了解 USB 描述符、端点和接口概念。开发者调用 navigator.usb.requestDevice() 时传入过滤器,用户从弹出的设备列表中选择。连接后调用 device.open()、device.selectConfiguration()、device.claimInterface(),然后通过 transferOut() 和 transferIn() 执行批量传输。

const device = await navigator.usb.requestDevice({
  filters: [{ vendorId: 0x2341 }]
});
await device.open();
await device.selectConfiguration(1);
await device.claimInterface(0);

// 发送数据到端点 1
await device.transferOut(1, new Uint8Array([0x01, 0x02]));

WebHID 则面向键盘、鼠标、游戏手柄等人机接口设备。它的优势是系统 HID 驱动不要求设备提供厂商驱动,浏览器可以直接读取输入报告和发送输出报告。与 WebUSB 相比,WebHID 更轻量,但只适用于 HID 协议设备。

三者选择上,可以先判断系统是否将设备识别为串口;如果是则 Web Serial 最简单。若设备有自定义 USB 描述符且需要底层控制,用 WebUSB。若是游戏控制器、传感器面板等 HID 设备,用 WebHID。不要试图用 WebUSB 访问已经由操作系统独占的鼠标键盘,否则会因接口被占用而失败。

Node.js 下使用 serialport 与硬件通信

在桌面端或服务端,Node.js 更适合长期运行硬件网关。serialport 是最常用的 npm 包,它封装了不同操作系统的串口 API,并支持事件驱动的数据接收。安装时可能需要在 Windows 上保留构建工具,但预编译二进制通常能覆盖主流 Node 版本。

下面的示例监听 COM3 或 /dev/ttyUSB0,并在收到数据后打印。serialport 默认会触发 data 事件,每次回调得到的是一小段 Buffer,同样需要处理粘包和半包问题。

const { SerialPort } = require('serialport');
const { ReadlineParser } = require('@serialport/parser-readline');

const port = new SerialPort({
  path: 'COM3',
  baudRate: 9600
});

const parser = port.pipe(new ReadlineParser({ delimiter: '\n' }));
parser.on('data', line => {
  console.log('收到:', line.trim());
});

Node.js 方案的优势是脱离浏览器沙箱,可以直接访问文件系统、TCP 服务,也能把硬件数据推送到 WebSocket。缺点是部署环境需要安装原生依赖,在受限服务器或边缘设备上可能增加维护成本。

serialport 的 list() 方法可以枚举本机串口,适合做设备自动发现。如果在 Linux 下遇到权限不足,通常需要把用户加入 dialout 组,或使用 udev 规则授权指定 USB 设备。

完整示例:用 Web Serial 读取 Arduino 温湿度数据

下面给出一个端到端的浏览器示例。Arduino 端使用 DHT11 读取温湿度,并通过 Serial 打印字符串。浏览器端点击按钮后连接串口,按行解析并更新页面。

Arduino 代码片段如下。它每秒发送一次数据,格式为 temp=26.5&humi=58。为了简化,示例不处理 DHT 读取失败的重试逻辑。

#include <DHT.h>

#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  Serial.print("temp=");
  Serial.print(t);
  Serial.print("&humi=");
  Serial.println(h);
  delay(1000);
}

浏览器端建立连接后,用 ReadableStream 的 reader 逐块读取。数据按 \n 拆分并判断是否包含 temp= 字段,然后更新 DOM。

async function startMonitor() {
  const port = await navigator.serial.requestPort();
  await port.open({ baudRate: 9600 });

  const decoder = new TextDecoder();
  let buffer = '';

  const reader = port.readable.getReader();
  while (true) {
    const { value, done } = await reader.read();
    if (done) {
      reader.releaseLock();
      break;
    }
    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n');
    buffer = lines.pop();

    for (const line of lines) {
      if (line.startsWith('temp=')) {
        const [tempPart, humiPart] = line.split('&');
        document.getElementById('temp').textContent = tempPart.split('=')[1];
        document.getElementById('humi').textContent = humiPart.split('=')[1];
      }
    }
  }
}

该示例展示了硬件交互中最常见的模式:连续流、文本协议、按行拆包。如果数据量大,可以改为二进制协议,例如前两个字节表示长度,后面跟随负载。这样能避免文本解析延迟,也适合传输固件或图像数据。

安全边界与常见坑

浏览器硬件 API 都遵循权限最小化原则。Web Serial 没有设备列表 API,必须由用户手动选择端口;WebUSB 和 WebHID 也要求用户手势发起请求。任意页面不能在后台静默连接硬件,否则会带来严重隐私风险。

常见坑之一是误用波特率。Arduino 默认 9600,但很多现代开发板使用 115200。如果串口打开成功但数据乱码,先检查两端波特率是否一致。另一个坑是忘记释放 reader 或 writer 锁,导致后续端口无法再次打开或写入。

在 Windows 平台,Web Serial 可能因为驱动问题无法枚举某些 USB 转串口芯片。此时应确认设备管理器里是否出现 COM 端口,并安装芯片厂商驱动。Node.js 下 serialport 对 CH340、CP2102 等芯片兼容性较好,但仍需注意 Native 模块与 Electron 版本匹配。

最后,不要在生产环境长期打开浏览器页来采集硬件数据。标签页被后台节流后定时器和部分流操作可能受影响。更适合的架构是 Node.js 服务作为硬件网关,浏览器只做展示与控制端,通过 WebSocket 或 HTTP 与网关通信。

JavaScript硬件交互Web Serial APIWebUSB修改时间:2026-10-05 02:01:54

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1005/65792.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。