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

如何将蓝牙独立回调响应关联到Promise.resolve实现sendData方法Promisify

实现方案

由于蓝牙响应是全局监听器统一接收,你需要用队列/映射表存储每次请求的resolve/reject回调,收到响应后匹配对应回调执行即可,分两种常见场景实现:


场景1:设备响应按请求顺序返回(绝大多数低功耗蓝牙设备适用)

蓝牙设备通常会按请求发送的先后顺序返回响应,用队列存储回调即可:

  1. 连接设备时初始化回调队列,全局只注册一次响应监听器
device.connect().then(device => {
  // 存储待响应的请求回调队列
  device._responseQueue = [];

  // 全局响应监听器,收到响应后执行队列最前面的回调
  device.registerResponseListener((data) => {
    if (device._responseQueue.length) {
      const { resolve } = device._responseQueue.shift();
      resolve(data);
    }
  });

  // 可选:添加断开连接监听,清空所有待处理请求避免内存泄漏
  device.registerDisconnectListener(() => {
    device._responseQueue.forEach(({ reject }) => reject(new Error('设备已断开连接')));
    device._responseQueue = [];
  });
})
  1. 封装带超时的Promisified sendData 方法
const sendData = (device, data, timeout = 10000) => {
  return new Promise((resolve, reject) => {
    const requestItem = { resolve, reject };
    // 先把当前请求的回调加入队列
    device._responseQueue.push(requestItem);

    // 超时处理,避免请求丢失导致Promise永久pending
    const timer = setTimeout(() => {
      const index = device._responseQueue.indexOf(requestItem);
      if (index > -1) device._responseQueue.splice(index, 1);
      reject(new Error('请求超时,未收到设备响应'));
    }, timeout);

    try {
      device.write(data);
    } catch (err) {
      // 发送失败清理资源
      clearTimeout(timer);
      const index = device._responseQueue.indexOf(requestItem);
      if (index > -1) device._responseQueue.splice(index, 1);
      reject(err);
    }
  });
}

场景2:设备响应带请求唯一标识(支持并发请求无错配)

如果你的蓝牙协议里定义了请求ID字段,响应会携带对应请求的ID,可以用映射表存储回调,不用依赖顺序,更稳定:

  1. 连接设备时初始化映射表
device.connect().then(device => {
  // 用请求ID作为key存储回调
  device._responseMap = new Map();

  device.registerResponseListener((data) => {
    const reqId = data.requestId; // 取响应里携带的请求ID
    if (device._responseMap.has(reqId)) {
      const { resolve, timer } = device._responseMap.get(reqId);
      clearTimeout(timer);
      device._responseMap.delete(reqId);
      resolve(data);
    }
  });
})
  1. 封装sendData方法,每次生成唯一ID携带在请求中
const sendData = (device, data, timeout = 10000) => {
  return new Promise((resolve, reject) => {
    // 生成唯一请求ID
    const reqId = Math.random().toString(36).slice(2);
    // 把请求ID加入发送的数据中
    const payload = { ...data, requestId: reqId };

    const timer = setTimeout(() => {
      device._responseMap.delete(reqId);
      reject(new Error('请求超时'));
    }, timeout);

    device._responseMap.set(reqId, { resolve, timer });

    try {
      device.write(payload);
    } catch (err) {
      clearTimeout(timer);
      device._responseMap.delete(reqId);
      reject(err);
    }
  });
}

注意事项

  • 必须添加超时逻辑,避免设备无响应时内存泄漏
  • 若存在并发发送请求的场景,优先选择带请求ID的实现方案
  • 设备断开、报错时要清空所有待处理的Promise回调

内容的提问来源于stack exchange,提问作者T3db0t

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 18:15:02