问题
I currently have difficulties to structure my NodeJS project. I followed several YouTube series, seeing people using different techniques to structure their code. Which structure would you suggest me in my case? What's best practice?
I've my app.js
which contains connection establishment to MongoDB, initializing express, bodyParser, pug as view engine and finally starting the server.
My router.js
contains all routes and unfortunately some middleware code, which I want to move into their own dedicated controller.
The models
folder holds all schema files for MongoDB.
// File structure:
.
├─ controllers
| ├─ morticians.js
| ├─ people.js
| └─ pickups.js
├─ models
| ├─ mortician.js
| ├─ person.js
| └─ pickup.js
├─ views
| ├─ elements
| | └─ ..
| ├─ pages
| | ├─ dashboard.pug
| | └─ ..
| └─ layout.pug
├─ app.js
└─ router.js
We're a hospital an sometimes people die here. A mortician comes and picks them up, but the process to remove this person from our systems isn't automated yet. That's what this webapp is for. Pulling all deceased from our database, displaying them in the webapp and removing it as soon as the mortician came and picked that person up.
1. When the main-page is requested, it finds all people, then all morticians from MongoDB and finally rendering the page. I can imagine, that this not best practice, but how to refactor it?
// snippet router.js
const Person= require('./models/person')
const Mortician = require('./models/mortician')
router.get('/', (req, res, next) => {
Person.find({ pickedUp: false }, (err, people) => {
Mortician.find({}, (err, morticians) => {
if (err) return console.log(err);
res.render('pages/dashboard', {
title: 'Dashboard',
persons: people,
morticians: morticians
})
})
})
}
I tried moving the MongoDB operations into their controller
files, like this. It worked, but I'm unsure since it's using multiple promises and not really simplifying things:
// snippet router.js
const ConPeople = require('./controllers/people')
const ConMorticians = require('./controllers/morticians')
router.get('/',
(req, res, next) => {
res.locals.options = { pickedUp: false }
ConPeople.find(req, res, next)
.then((people) => {
res.locals.people = people
next()
})
},
(req, res, next) => {
res.locals.options = {}
ConMorticians.find(req, res, next)
.then((morticians) => {
res.locals.morticians = morticians
next()
})
},
(req, res) => {
res.render('pages/dashboard', {
title: 'Dashboard',
people: res.locals.people,
morticians: res.locals.morticians.reverse()
})
}
)
// snippet controllers/people.js
module.exports = {
find: (req, res, next) => {
return Person.find(res.locals.options)
}
}
2. In some cases I need to execute commands like deleting or adding a person from MongoDB. For example, a mortician comes and picks up a person. I need to set the status of that person to pickedUp = true
, eventually add a new mortician if that's provided and add a new document to the collection pickups
. How do I do that without having to rewrite the same lines?
回答1:
There are 2 things which, when used in combination, will make the code much nicer:
Collection.find
returns a Promise.- To wait for a Promise to resolve in modern Javascript, use
await
You can use the following code:
const Person= require('./models/person')
const Mortician = require('./models/mortician')
router.get('/', async (req, res, next) => {
try {
const persons = await Person.find({ pickedUp: false });
const morticians = await Mortician.find({});
res.render('pages/dashboard', {
title: 'Dashboard',
persons,
morticians,
});
} catch(e) {
// handle errors
}
});
Or, to retrieve the results in parallel rather than in serial, use Promise.all
:
router.get('/', async (req, res, next) => {
try {
const [persons, morticians] = await Promise.all([
Person.find({ pickedUp: false }),
Mortician.find({})
]);
res.render('pages/dashboard', {
title: 'Dashboard',
persons,
morticians,
});
} catch(e) {
// handle errors
}
});
You can use the same sort of pattern whenever you have multiple asynchronous calls to make - no need for ugly bracket nesting and indentation.
来源:https://stackoverflow.com/questions/61726347/refactoring-middleware-code-of-nodejs-project-using-routes-controllers-and-mod