Node.js Express中如何用await/.then处理Logix.js异步导出变量?
解决方案
方案1:导出Promise等待首次数据,结合getter获取最新值
修改Logix.js,通过Promise通知主模块首次数据就绪,同时用getter确保每次访问都是最新的轮询数据:
"use-strict"; const PLC = require("node-logix").default; PLC.defaultOptions.Micro800 = true; const comm = new PLC("192.168.0.5"); let arr1 = []; let interval1 = null; // 创建Promise,首次获取数据后resolve const firstDataReady = new Promise((resolve, reject) => { comm.on("connect", async () => { console.log("PLC connected successful! "); try { // 先执行一次数据读取,完成后resolve const data = await comm.read("SETTINGS", { count: 10 }); arr1 = data.splice(0); resolve(arr1); // 启动定时轮询 interval1 = setInterval(poolData, 1500); } catch (err) { reject(err); } }); comm.on("connect_error", (err) => { reject(err); }); }); comm.connect().catch(console.error); comm.on("disconnect", reason => { if (interval1) clearInterval(interval1); console.log("PLC disconnected reason:", reason); }); async function poolData() { try { const data = await comm.read("SETTINGS", { count: 10 }); arr1 = data.splice(0); } catch (err) { console.error("读取PLC数据失败:", err); } } // 导出Promise和实时数据的getter module.exports = { get arr1() { return arr1; }, waitForFirstData: () => firstDataReady };
在index.js中,用async函数等待Promise完成,路由中直接通过getter获取最新数据:
/*Required External Modules*/ const express = require("express"); const path = require("path"); const moduleL = require('./Logix.js'); /*App Variables*/ const app = express(); const port = process.env.PORT || "8000"; let arr1 = []; // 等待首次PLC数据就绪 (async () => { try { arr1 = await moduleL.waitForFirstData(); console.log("首次数据加载完成: " + arr1); } catch (err) { console.error("PLC连接或数据读取失败:", err); } })(); /*App Configuration*/ app.set("views", path.join(__dirname, "views")); app.set("view engine", "pug"); app.use(express.static(path.join(__dirname, "public"))); /*Routes Definitions*/ app.get("/", (req, res) => { res.render("index", { title: "Home" }); }); app.get("/user", (req, res) => { // 直接获取最新的轮询数据 res.render("user", { title: "Profile", userProfile: moduleL.arr1 }); }); /*Server Activation*/ app.listen(port, () => { console.log(`Listening to requests on http://localhost:${port}`); });
方案2:用事件系统实时感知数据更新
如果需要实时响应数据变化,可借助Node的EventEmitter触发更新事件:
"use-strict"; const PLC = require("node-logix").default; const EventEmitter = require('events'); PLC.defaultOptions.Micro800 = true; const comm = new PLC("192.168.0.5"); const emitter = new EventEmitter(); let arr1 = []; let interval1 = null; comm.on("connect", () => { console.log("PLC connected successful! "); interval1 = setInterval(poolData, 1500); }); comm.connect().catch(console.error); comm.on("connect_error", e => { console.log("Fail to connect PLC!"); emitter.emit('error', e); }); comm.on("disconnect", reason => { if (interval1) clearInterval(interval1); console.log("PLC disconnected reason:", reason); }); async function poolData() { try { const data = await comm.read("SETTINGS", { count: 10 }); arr1 = data.splice(0); // 触发数据更新事件,传递最新数据 emitter.emit('dataUpdated', arr1); } catch (err) { console.error("读取PLC数据失败:", err); emitter.emit('error', err); } } // 导出getter和事件监听方法 module.exports = { get arr1() { return arr1; }, on: emitter.on.bind(emitter), once: emitter.once.bind(emitter) };
index.js中监听事件,处理首次和后续数据更新:
/*Required External Modules*/ const express = require("express"); const path = require("path"); const moduleL = require('./Logix.js'); /*App Variables*/ const app = express(); const port = process.env.PORT || "8000"; let arr1 = moduleL.arr1; // 等待首次数据更新 moduleL.once('dataUpdated', (newData) => { arr1 = newData; console.log("首次数据加载完成: " + arr1); }); // 监听后续数据更新 moduleL.on('dataUpdated', (newData) => { arr1 = newData; console.log("数据已更新: " + arr1); }); // 监听错误 moduleL.on('error', (err) => { console.error("PLC操作出错:", err); }); /*App Configuration*/ app.set("views", path.join(__dirname, "views")); app.set("view engine", "pug"); app.use(express.static(path.join(__dirname, "public"))); /*Routes Definitions*/ app.get("/", (req, res) => { res.render("index", { title: "Home" }); }); app.get("/user", (req, res) => { res.render("user", { title: "Profile", userProfile: moduleL.arr1 }); }); /*Server Activation*/ app.listen(port, () => { console.log(`Listening to requests on http://localhost:${port}`); });
核心要点
- 直接导出变量时,Node模块同步加载会拿到初始空数组,后续变量引用更新无法自动通知主模块,因此需要借助Promise或事件系统实现异步等待。
- 使用getter可以确保每次访问
moduleL.arr1时都获取最新的轮询数据,避免引用失效问题。 - 方案1适合只需要等待首次数据,后续直接取最新值的场景;方案2适合需要实时响应数据变化的场景。
内容的提问来源于stack exchange,提问作者simonmarkis
相关产品推荐
相关产品推荐

