Node.js中BLE设备0-59内存地址循环读写回调执行异常问题
The root issue here is that BLE write and read operations are asynchronous. If you tried a plain for loop, it would fire all 60 write requests at once, overwhelming the device and causing read callbacks to fail or execute out of order. We need to run these operations serially — finish one full "write → read → increment" cycle before starting the next.
Here are two robust solutions depending on your JavaScript environment:
Option 1: Using Async/Await (Cleanest & Most Readable)
If your environment supports ES2017+ (most modern Node.js versions, Electron, etc.), async/await makes this logic straightforward. First, we'll wrap the callback-based BLE methods in Promises, then use a standard loop with await to enforce sequential execution:
// Wrap BLE write/read into Promises for async/await compatibility function writeCharacteristic(data) { return new Promise((resolve, reject) => { SensorCharacteristic.write(data, false, (error) => { error ? reject(error) : resolve(); }); }); } function readCharacteristic() { return new Promise((resolve, reject) => { SensorCharacteristic.read((error, data) => { error ? reject(error) : resolve(data); }); }); } // Main function to read all addresses from 0 to 59 async function readAllMemoryAddresses(startAddr = 0, endAddr = 59) { for (let addr = startAddr; addr <= endAddr; addr++) { // Build the command string: AAAD00 + 2-digit hex address (padded with zero if needed) const hexAddr = addr.toString(16).padStart(2, '0').toUpperCase(); const mydata = `AAAD00${hexAddr}`; console.log(`Processing address 0x${hexAddr}, command: ${mydata}`); try { // Step 1: Write the command to the characteristic await writeCharacteristic(Buffer.from(mydata, 'hex')); console.log('Writing command SUCCESSFUL', mydata); // Step 2: Read the response from the characteristic const data = await readCharacteristic(); console.log("Entered read callback"); const hexData = data.toString('hex'); if (hexData !== '0000') { console.log(`Temperature History (0x${hexAddr}):`, hexData); } else { console.log(`Address 0x${hexAddr} contains null value`); } // Optional: Add a small delay to avoid overwhelming the device await new Promise(resolve => setTimeout(resolve, 100)); } catch (error) { console.error(`Failed to process address 0x${hexAddr}:`, error); // Continue to next address even if current one fails continue; } } console.log('All memory addresses processed successfully!'); } // Start the loop readAllMemoryAddresses();
Key Benefits:
- Synchronous-style code that's easy to follow and debug
- Automatic sequential execution (no race conditions)
- Proper error handling to prevent a single failure from breaking the entire loop
- Ensures the address is always 2 hex digits (e.g., address 9 becomes
09, address 10 becomes0A)
Option 2: Using Recursion (Compatible with Older Environments)
If you can't use async/await, a recursive function will achieve the same sequential flow. Each iteration calls itself only after the previous read/write cycle completes:
// Recursive function to process addresses one by one function readNextAddress(currentAddr = 0, endAddr = 59) { // Exit condition: we've processed all addresses if (currentAddr > endAddr) { console.log('All memory addresses processed successfully!'); return; } // Build the command string with 2-digit hex address const hexAddr = currentAddr.toString(16).padStart(2, '0').toUpperCase(); const mydata = `AAAD00${hexAddr}`; console.log(`Processing address 0x${hexAddr}, command: ${mydata}`); const buff2 = Buffer.from(mydata, 'hex'); SensorCharacteristic.write(buff2, false, function(error) { if (error) { console.error(`Failed to write to 0x${hexAddr}:`, error); // Move to next address even if write fails readNextAddress(currentAddr + 1, endAddr); return; } console.log('Writing command SUCCESSFUL', mydata); SensorCharacteristic.read((error, data) => { if (error) { console.error(`Failed to read from 0x${hexAddr}:`, error); readNextAddress(currentAddr + 1, endAddr); return; } console.log("Entered read callback"); const hexData = data.toString('hex'); if (hexData !== '0000') { console.log(`Temperature History (0x${hexAddr}):`, hexData); } else { console.log(`Address 0x${hexAddr} contains null value`); } // Optional delay before next iteration setTimeout(() => { readNextAddress(currentAddr + 1, endAddr); }, 100); }); }); } // Start the recursive loop readNextAddress();
Key Notes:
- Recursion ensures we never send concurrent requests to the device
- Error handling keeps the loop running even if one address fails
- The optional
setTimeoutgives the device time to process each request (adjust the delay based on your device's responsiveness)
Critical Things to Remember:
- Always pad the address to 2 hex digits: Using
padStart(2, '0')ensures your command stays in theAAAD00xxformat — no invalid commands likeAAAD00Afor address 10. - Respect device limits: Some BLE devices can't handle back-to-back operations immediately, so the optional delay is a good safety measure.
- Error handling: Don't skip this! A single failed read/write shouldn't stop your entire data collection.
内容的提问来源于stack exchange,提问作者APARNA

