具有仅发生一次的异步操作的 Express 中间件
Express middleware with async operation that happens only once
我正在尝试使用中间件将一些数据附加到我的请求对象,但我只想在服务器启动后执行此操作。
所以我尝试用中间件来做,同时尝试使用函数的上下文,但是在中间件上执行这样的操作有点问题,因为我不能将承诺作为中间件传递。
这就是我想要做的:
const setupData = async () => {
const data = await getSomeData();
return (req, res, next) => {
req.data = data;
next();
}
}
app.use(setupData());
我尝试使用建议的解决方案 ,但它不起作用,因为每次请求都会发生这种情况。
知道我该如何解决这个问题吗?我总是可以将信息放在全局变量中,但我想避免它。
我还看到了一些内存包来帮助它(例如node-cache),但我想用中间件来做。
提前致谢
你可以在没有异步的情况下做到这一点:-
const setupData = (req, res, next) => {
// You can put a condition here so that it runs only once
getSomeData().then((data) => {
req.app.locals.data = data //The data can be accessed in the next middleware using req.app.locals
next();
}).catch((error) => {
console.log("Error Occured");
res.status(400).end("Error Occurred");
})
}
app.use(setupData);
您应该查看 getSomeData
的文档并了解其工作原理
只需使用普通变量缓存结果:
let data = null;
function setupData (req, res, next) {
if (data !== null) {
req.data = data;
next();
}
else {
getSomeData().then(result => {
data = result
req.data = data;
next();
});
}
}
app.use(setupData);
这是最小的、最不复杂的实现。您当然可以通过删除缓存逻辑将其重构为更干燥并且更不容易出错:
更简洁的实施
let cache = null;
async function getCachedData() {
if (cache === null) {
cache = await getSomeData();
}
return cache;
}
这使得 setupData
更干净:
function setupData (req, res, next) {
getCachedData().then(data => {
req.data = data;
next();
});
}
无论哪种方式,都会在第一次请求时触发缓存。这意味着有可能在数据可能被缓存之前第二个请求到达。所以在启动时 getSomeData()
函数可能 运行 不止一次。
真的只调用一次 getSomeData()
如果您真的只想调用 getSomeData
一次,您 必须 在设置 Express 之前调用它:
async function main () {
const data = await getSomeData();
const app = express();
//
// set up express middlewares...
//
app.use((req,res,next) => {
req.data = data;
next();
});
//
// set up routes...
//
app.listen(config.port);
}
main(); // start everything
这里的关键是要意识到我们一直在尝试向后做所有事情:异步设置一个常量值在 开始设置 Express 之后。程序的自然流程希望常量值存在 BEFORE 我们开始设置 Express,因此我们只在异步函数(此处称为 main
)中执行其他所有操作。在设置 Express 时不要尝试 运行 异步功能。
我正在尝试使用中间件将一些数据附加到我的请求对象,但我只想在服务器启动后执行此操作。 所以我尝试用中间件来做,同时尝试使用函数的上下文,但是在中间件上执行这样的操作有点问题,因为我不能将承诺作为中间件传递。
这就是我想要做的:
const setupData = async () => {
const data = await getSomeData();
return (req, res, next) => {
req.data = data;
next();
}
}
app.use(setupData());
我尝试使用建议的解决方案
知道我该如何解决这个问题吗?我总是可以将信息放在全局变量中,但我想避免它。 我还看到了一些内存包来帮助它(例如node-cache),但我想用中间件来做。
提前致谢
你可以在没有异步的情况下做到这一点:-
const setupData = (req, res, next) => {
// You can put a condition here so that it runs only once
getSomeData().then((data) => {
req.app.locals.data = data //The data can be accessed in the next middleware using req.app.locals
next();
}).catch((error) => {
console.log("Error Occured");
res.status(400).end("Error Occurred");
})
}
app.use(setupData);
您应该查看 getSomeData
的文档并了解其工作原理
只需使用普通变量缓存结果:
let data = null;
function setupData (req, res, next) {
if (data !== null) {
req.data = data;
next();
}
else {
getSomeData().then(result => {
data = result
req.data = data;
next();
});
}
}
app.use(setupData);
这是最小的、最不复杂的实现。您当然可以通过删除缓存逻辑将其重构为更干燥并且更不容易出错:
更简洁的实施
let cache = null;
async function getCachedData() {
if (cache === null) {
cache = await getSomeData();
}
return cache;
}
这使得 setupData
更干净:
function setupData (req, res, next) {
getCachedData().then(data => {
req.data = data;
next();
});
}
无论哪种方式,都会在第一次请求时触发缓存。这意味着有可能在数据可能被缓存之前第二个请求到达。所以在启动时 getSomeData()
函数可能 运行 不止一次。
真的只调用一次 getSomeData()
如果您真的只想调用 getSomeData
一次,您 必须 在设置 Express 之前调用它:
async function main () {
const data = await getSomeData();
const app = express();
//
// set up express middlewares...
//
app.use((req,res,next) => {
req.data = data;
next();
});
//
// set up routes...
//
app.listen(config.port);
}
main(); // start everything
这里的关键是要意识到我们一直在尝试向后做所有事情:异步设置一个常量值在 开始设置 Express 之后。程序的自然流程希望常量值存在 BEFORE 我们开始设置 Express,因此我们只在异步函数(此处称为 main
)中执行其他所有操作。在设置 Express 时不要尝试 运行 异步功能。