Node.js Express中间件,异步操作只发生一次

Node.js Express中间件,异步操作只发生一次,node.js,express,async-await,middleware,Node.js,Express,Async Await,Middleware,我试图使用中间件将一些数据附加到我的请求对象,但我只想在服务器启动后执行。 因此,我尝试使用中间件,同时尝试使用函数的上下文,但在中间件上执行这样的操作有点问题,因为我无法作为中间件传递承诺 这就是我想做的: const setupData=async()=>{ const data=等待getSomeData(); 返回(请求、恢复、下一步)=>{ req.data=数据; next(); } } app.use(setupData()); 我尝试使用建议的解决方案,但它不起作用,因为每次请

我试图使用中间件将一些数据附加到我的请求对象,但我只想在服务器启动后执行。 因此,我尝试使用中间件,同时尝试使用函数的上下文,但在中间件上执行这样的操作有点问题,因为我无法作为中间件传递承诺

这就是我想做的:

const setupData=async()=>{
const data=等待getSomeData();
返回(请求、恢复、下一步)=>{
req.data=数据;
next();
}
}
app.use(setupData());
我尝试使用建议的解决方案,但它不起作用,因为每次请求都会出现这种情况

你知道我该怎么做吗?我总是可以把信息放在一个全局变量上,但我想避免它。 我还看到了一些内存中的包来帮助实现它(例如),但我希望使用中间件来实现它


提前感谢

无需异步即可完成:-

const setupData=(请求、恢复、下一步)=>{
//您可以在此处设置一个条件,使其仅运行一次
getSomeData()。然后((数据)=>{
req.app.locals.data=data//可以在下一个中间件中使用req.app.locals访问数据
next();
}).catch((错误)=>{
console.log(“发生错误”);
res.status(400)。结束(“发生错误”);
})
}
应用程序使用(设置数据);

您应该查看
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);
这是最小、最不复杂的实现。当然,通过去掉缓存逻辑,您可以将其重构为更干爽、更不容易出错:

更清洁的实施 这使得
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之后异步设置一个常量值。程序的自然流程希望常量值在开始设置Express之前存在,因此我们只执行异步函数(这里称为
main
)中的所有其他操作。设置Express时不要尝试运行异步函数。

谢谢,但这样做行不通。您没有真正传递req、res和
setupData
函数旁边的值。即使你这样做了,那也会让你回到原来的问题,我希望它只在看到更新的答案后才会发生。
req,res,next
正在函数中传递。谢谢,但正如我提到的-我希望在加载应用程序时只发生一次。您的解决方案将获取每个请求的数据。设置if-else条件,以便在变量已设置时不会获取数据。是的,这就是我的想法。我想避免这种解决方案,但看起来我没有其他选择,我想避免。我认为还有另一种更优雅的方式。@matmiz重构缓存逻辑非常优雅。你可以把它塞进一个模块,却看不到它的机制。如果你使用第三方库做类似的事情,比如jQuery、knex、rxjs或React等,也是一样的。它们都保持着混乱的状态,但我们永远不需要看到itThanks@slebetman。你们编辑的答案现在已经很清楚了,你们有一个很好的观点(在你们的评论中也是如此)。干杯如果您没有足够的时间编写
main()
函数,那么了解缓存解决方案仍然非常有用。例如,如果要发布库/模块供其他人使用。在内部,这就是knex或mysql等库存储连接的方式。请注意,大多数db库都有类似于同步API的设置连接的功能。但事实上,连接只是在第一个请求时创建的,然后被缓存-类似于上面的缓存逻辑,但通常更复杂,因为它们也尝试共享连接
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