点击按钮替换数组旧值为新值的BLE Web应用开发问题
解决方案
要解决多次扫描导致数组持续变长的问题,需从重置数组、避免重复事件监听器、按固定索引更新数据三个维度修改代码:
1. 每次扫描前重置全局数组
由于devices、ids、distances是全局常量数组,无法直接重新赋值,可通过length = 0清空数组内容,确保每次扫描从空状态开始收集数据。
2. 移除重复的事件监听器
每次调用scan()会新增advertisementreceived监听器,多次点击会导致多个监听器同时工作。需保存监听器引用,在扫描结束或出错时移除。
3. 按固定索引更新设备数据
利用beaconMapping中定义的设备索引,直接替换数组对应位置的元素,而非使用push()追加,确保数组长度始终固定为3。
修改后的完整代码
import * as trilateration from './trilateration.js'; import context from './context.js'; const beaconMapping = { 'ESP32_1': 0, 'ESP32_2': 1, 'ESP32_3': 2, } const DISTANCE_SCALAR = 1; console.log("Init"); const devices = []; const ids = []; const beaconuuid = []; const distances = []; let advertisementListener; // 保存事件监听器引用 const SCAN_TIME = 10000; // 添加基站到三边定位系统 trilateration.addBeacon(0, trilateration.vector(10.1, 7.0)); trilateration.addBeacon(1, trilateration.vector(0, 0)); trilateration.addBeacon(2, trilateration.vector(10.1, 0)); document.getElementById("scan").onclick = scan; async function scan() { console.log("Scanning..."); // 重置全局数组,清空上次扫描数据 devices.length = 0; ids.length = 0; distances.length = 0; let options = { acceptAllAdvertisements: true, acceptAllDevices: true, }; try { log("Requesting Bluetooth Scan with options: " + JSON.stringify(options)); const scan = await navigator.bluetooth.requestLEScan(options); log("Scan started with:"); log(" acceptAllAdvertisements: " + scan.acceptAllAdvertisements); log(" active: " + scan.active); log(" keepRepeatedDevices: " + scan.keepRepeatedDevices); log(" filters: " + JSON.stringify(scan.filters)); // 定义事件监听器并保存引用 advertisementListener = (event) => { let name = event.device.name; if (name && name.startsWith("ESP32")) { console.log("Found"); const obj = { device: event.device, uuids: event.uuids, rssi: event.rssi, tx: event.txPower, distance: calculateDistance(event.rssi, event.txPower) * DISTANCE_SCALAR, }; console.log(obj); console.log(obj.tx, obj.rssi, obj.distance, name); const beaconIndex = beaconMapping[event.device.name]; if (beaconIndex !== undefined) { // 按固定索引替换数据,而非push追加 devices[beaconIndex] = obj; ids[beaconIndex] = event.device.id; distances[beaconIndex] = obj.distance; trilateration.setDistance(beaconIndex, obj.distance); } else { console.error("Name not found in mapping"); } // 确保三个设备的数据都有效时再计算位置 if (distances.every(d => d !== undefined)) { var pos = trilateration.calculatePosition(); console.log(pos); console.log("Distances are length", distances.length) console.log("X: " + pos.x + "; Y: " + pos.y); context.fillRect(pos.x * 100, pos.y * 100, 20, 20); } showBeaconInfo(obj); } }; navigator.bluetooth.addEventListener("advertisementreceived", advertisementListener); setTimeout(stopScan, SCAN_TIME); function stopScan() { console.log("List of all devices detected:"); console.log(devices); console.log(ids) console.log(beaconuuid); console.log(distances) log("Stopping scan..."); // 移除事件监听器,避免重复监听 navigator.bluetooth.removeEventListener("advertisementreceived", advertisementListener); scan.stop(); log("Stopped. scan.active = " + scan.active); } } catch (error) { log("Argh! " + error); // 出错时也要移除监听器,防止内存泄漏 if (advertisementListener) { navigator.bluetooth.removeEventListener("advertisementreceived", advertisementListener); } } }
关键修改说明
- 数组重置:在
scan()开头通过length = 0清空数组,保证每次扫描的初始状态干净。 - 事件监听器管理:用变量保存监听器引用,扫描结束或出错时移除,避免多次点击导致多监听器同时触发。
- 固定索引更新:通过
beaconMapping获取的索引直接替换数组对应位置元素,确保数组长度始终为3,对应三个ESP设备。 - 位置计算条件优化:将
distances.length > 2改为distances.every(d => d !== undefined),避免部分设备未扫描到时的错误计算。
内容的提问来源于stack exchange,提问作者Milan Langhendries
相关产品推荐
相关产品推荐

