使用mqttjs连续发布多个Buffer时仅重复输出最后一个值问题求解
问题原因
这一问题是Node.js Buffer的引用类型特性与MQTT.js publish方法的异步执行逻辑共同导致的,和MQTT服务端、MQTT.js库本身的bug无关,属于JavaScript语法层面的常见误区。
具体原因拆解
- Node.js中的Buffer属于引用类型,你全程仅初始化了一个Buffer实例,所有对
buf[0]的修改都是在操作同一块内存地址存储的值,没有生成新的副本。 client.publish是异步方法,循环调用时仅会将发送任务推入Node.js事件队列,不会立刻执行网络发送操作。而for循环是同步执行的,等循环跑完时buf[0]已经被递增到0xff,事件队列中排队的多个publish任务才会依次执行,此时读取同一个Buffer拿到的都是最终的0xff值。
你观察到的特殊现象也完全符合该逻辑:先调用publish将发送任务入队后,同步执行的for循环会立刻将Buffer值修改为0xff,等publish实际执行读取Buffer内容时,拿到的自然已经是修改后的值。
而连续发布字符串没有问题,是因为字符串属于JavaScript值类型,传入publish时会自动传值而非传引用,后续修改不会影响已经入队的任务内容。
修复方案
方案1:循环内每次创建新的Buffer实例(推荐)
每次发布都生成独立的Buffer,互不干扰:
client.on('connect', function () { client.subscribe('LED', function (err) { if (!err) { for (let val = 0xfa; val < 0xff; val++) { const buf = Buffer.from([val]); client.publish('LED', buf); } } }) })
方案2:复用Buffer改为串行异步发送
如果需要复用同一个Buffer,需要等待前一条消息确认发送完成后,再修改Buffer值发送下一条:
// 先将publish封装为Promise适配async/await语法 const publishAsync = (client, topic, payload) => { return new Promise((resolve, reject) => { client.publish(topic, payload, (err) => err ? reject(err) : resolve()) }) } client.on('connect', async function () { client.subscribe('LED', async function (err) { if (!err) { const buf = Buffer.from([0xfa]); for (; buf[0] < 0xff; buf[0]++) { await publishAsync(client, 'LED', buf); } } }) })
内容的提问来源于stack exchange,提问作者Jdm
相关产品推荐
相关产品推荐

