我有一个Express应用程序,我正在尝试将所有中间件放在其自己的文件中。一些中间件功能需要db
对象,而某些则不需要。
对于不需要db
对象的函数来说,这非常简单,但是鉴于下面的代码结构,如何在db
中引用doesNotNeedDbParam
对象,因为它已经具有参数req
,res
和next
?
somefile.js:
const router = express.Router()
const doesNotNeedDbParam = require('./middleware')().doesNotNeedDbParam
function foo () {
// Currently I have to call require and pass in the db object here b/c
// it's not set when requiring the function doesNotNeedDbParam
router.use(require('./middleware')(db).needsDbParam // <-- Is there a better way to do this so that I can require the file above and pass the db object in when it's set?
}
// Setup db object here
foo()
middleware.js
function doesNotNeedDbParam (req, res, next) {
...
}
function needsDbParam (req, res, next) {
// Where do I reference the db variable?
}
module.exports = (db) => {
return {
doesNotNeedDbParam: doesNotNeedDbParam,
needsDbParam: needsDbParam
}
}
答案 0 :(得分:8)
我认为,一个不错的结构是尝试currying您的中间件。这种模式是由body-parser
之类的中间件实践的,而Express serve-static
在内部则是一种实践。这样,您只需要一次,并在需要的地方传递db
,而在不需要的地方传递:{p>
// Instead of declaring each function directly as a middleware function,
// we declare them as a function that returns a middleware function
function doesNotNeedDbParam () {
return function (req, res, next) {
…
}
}
function needsDbParam (db) {
return function (req, res, next) {
// You can use db here along with req, res, next
}
}
// No need to export a function now
module.exports = {
doesNotNeedDbParam,
needDbParam,
};
然后,只需:
const middleware = require('./middleware');
…
router.use(middleware.doesNotNeedDbParam()); // Since this doesn't need anything, no argument
router.use(middleware.needsDbParam(db)); // You can pass db here now
如果您熟悉ES6 +语法,可以凝结为:
const doesNotNeedDbParam = () => (req, res, next) => {
…
}
const needsDbParam = (db) => (req, res, next) => {
// Use db here
}
// Export object here...
然后:
const { doesNotNeedDbParam, needsDbParam } = require('./middleware');
…
router.use(doesNotNeedDbParam());
router.use(needsDbParam(db));
还有另一种方法,可以将属性附加到req
对象 一次。这样一来,您就不必在每次需要时都重新输入db
。许多其他软件包也使用这种策略。它是这样的:
function attachDb (db) { // Still use curry approach here since we want db
return function (req, res, next) {
// Attaches the specified db to req directly
req.db = db;
}
}
function needsDbParam (req, res, next) { // No need for currying
// Now use req.db here
}
// Export your other middleware…
然后,像这样使用它,请确保attachDb
是 first ,以便在使用属性之前先分配该属性:
router.use(attachDb(db)); // Before all other middleware that depend on req.db
…
// No need to call because this is already the middleware function,
// able to use req.db, which was assigned via attachDb
router.use(needDbParam);
答案 1 :(得分:-1)
为什么不仅仅将module.exports
声明为一个函数:
module.exports = (db) => {
let module = {};
module.doesNotNeedDbParam = (req, res) => {
// Do Stuff
};
module.needsDbParam = (req, res) => {
// db now in scope
};
return module;
};
这就是您的somefile.js
将会变成的:
const router = express.Router();
const db = initializeDb();
const doesNotNeedDbParam = require('./middleware')().doesNotNeedDbParam;
router.use(require('./middleware')(db).needsDbParam);
您也可以像这样设置一次:
const middleware = require('./middleware')(db);
const doesNotNeedParam = middleware.doesNotNeedParam;
router.use(middleware.needsDbParam);
这与您之前所做的并没有什么不同,但是现在您可以访问needsDbParam
中的db了。如果您的initializeDb
函数是异步的,那么在建立数据库之后,您将需要使用Promise
或其他一些异步库来包括在内。