Javascript 函数中的Mongoose查询承诺使代码变得丑陋
我正在创建我的用户API,我想检查是否使用了用户名。 所以我写了一个静态函数Javascript 函数中的Mongoose查询承诺使代码变得丑陋,javascript,node.js,express,mongoose,Javascript,Node.js,Express,Mongoose,我正在创建我的用户API,我想检查是否使用了用户名。 所以我写了一个静态函数 static findByName(name) { const query = User.where({ username: name, }); query.findOne((queryErr, user) => { if (queryErr) { console.log(queryErr); return false; } re
static findByName(name) {
const query = User.where({
username: name,
});
query.findOne((queryErr, user) => {
if (queryErr) {
console.log(queryErr);
return false;
}
return user;
});
}
当我叫它注册的时候
signup(req, res) {
if (!req.body.username || !req.body.password || !req.body.email) {
return res.status(400).json({ success: false, message: 'Bad Request' });
}
if (!Users.findByName(req.body.username)) {
return res.status(409).json({ success: false, message: 'Username has been used' });
}
const hashedPassword = this.genHash(req.body.password);
const newUser = User({
username: req.body.username,
});
}
findByName返回未定义。
最后我用承诺
signup(req, res) {
if (!req.body.username || !req.body.password || !req.body.email) {
return res.status(400).json({ success: false, message: 'Bad Request' });
}
return Users.findByName(req.body.username).then((existingUser) => {
if (existingUser) {
return res.status(409).json({ success: false, message: 'Username has been used' });
}
const hashedPassword = this.genHash(req.body.password);
const newUser = User({
username: req.body.username,
password: hashedPassword,
email: req.body.email,
});
return newUser.save().then((user) => {
res.json({ success: true, user });
}).catch((err) => {
res.status(500).json({ success: false, message: 'Internal Server Error' });
});
}).catch((err) => {
res.status(500).json({ success: false, message: 'Internal Server Error' });
});
}
这是非常可怕的代码。
有没有更好的方法来清理代码?我无法测试我的解决方案是否真的有效(可能不行),或者我是否涵盖了原始代码的所有功能。我试图做的是创建处理特定事物的函数,然后将它们链接在一起,这样您就可以看到更清晰的程序流程
signup(req, res) {
if (!req.body.username || !req.body.password || !req.body.email) {
return res.status(400).json({ success: false, message: 'Bad Request' });
}
const handleError = error => res.status(500).json({ success: false, message: 'Internal Server Error' });
const handleExistingUser = existingUser => {
if (existingUser) {
return res.status(409).json({ success: false, message: 'Username has been used' });
} else {
return Promise.resolve();
}
}
const handleCreateUser = () => {
const hashedPassword = this.genHash(req.body.password);
const newUser = User({
username: req.body.username,
password: hashedPassword,
email: req.body.email,
});
return newUser.save().then((user) => {
res.json({ success: true, user });
});
};
// the flow of the program is hopefully more clear here
return Users.findByName(req.body.username)
.then(handleExistingUser)
.then(handleCreateUser)
.catch(handleError);
}
如果处理内部和外部承诺的错误是一样的,那么我认为在外层处理错误就足够了。(在您的最后一个示例中)但我不是100%确定。我无法测试我的解决方案是否实际工作(可能不工作),或者我是否涵盖了您原始代码的所有功能。我试图做的是创建处理特定事物的函数,然后将它们链接在一起,这样您就可以看到更清晰的程序流程
signup(req, res) {
if (!req.body.username || !req.body.password || !req.body.email) {
return res.status(400).json({ success: false, message: 'Bad Request' });
}
const handleError = error => res.status(500).json({ success: false, message: 'Internal Server Error' });
const handleExistingUser = existingUser => {
if (existingUser) {
return res.status(409).json({ success: false, message: 'Username has been used' });
} else {
return Promise.resolve();
}
}
const handleCreateUser = () => {
const hashedPassword = this.genHash(req.body.password);
const newUser = User({
username: req.body.username,
password: hashedPassword,
email: req.body.email,
});
return newUser.save().then((user) => {
res.json({ success: true, user });
});
};
// the flow of the program is hopefully more clear here
return Users.findByName(req.body.username)
.then(handleExistingUser)
.then(handleCreateUser)
.catch(handleError);
}
如果处理内部和外部承诺的错误是一样的,那么我认为在外层处理错误就足够了。(在你最后的例子中)但我不是100%肯定
有没有更好的方法来清理代码
对。我将假定/signup
被定义为普通Express应用程序
实例上的POST
路线
说到这里,既然您已经在使用承诺,那么您可以更进一步,使用Node.jsv7.6+中默认启用的承诺
这将使您的代码读取更加同步:
async signup(req, res) {
if (!req.body.username || !req.body.password || !req.body.email) {
return res.status(400).json({ success: false, message: 'Bad Request' });
}
try {
const existingUser = await Users.findByName(req.body.username)
if (existingUser) {
return res.status(409).json({ success: false, message: 'Username has been used' })
}
const hashedPassword = this.genHash(req.body.password);
const newUser = await User({
username: req.body.username,
password: hashedPassword,
email: req.body.email,
}).save()
res.json({ success: true, newUser });
} catch (error) {
res.status(500).json({ success: false, message: 'Internal Server Error' });
}
}
您可能已经注意到使用了try/catch
。这是因为我们没有使用.catch()
,因此我们仍然必须处理发生的任何错误。为了进一步清理代码,我们可以编写一个错误处理程序中间件来为我们处理错误:
src/middleware/error handlers.js
// Wraps the router handler, catches any errors, and forwards to the next middleware that handles errors
exports.catchErrors = action => (req, res, next) => action(req, res).catch(next);
// Notice the first parameter is `error`, which means it handles errors.
exports.displayErrors = (error, req, res, next) => {
const err = error;
const status = err.status || 500;
delete err.status;
err.message = err.message || 'Something went wrong.';
if (process.env.NODE_ENV === 'production') {
delete err.stack;
} else {
err.stack = err.stack || '';
}
res.status(status).json({
status,
error: {
message: err.message,
},
});
};
const { catchErrors, displayErrors } = require('./middleware/error-handlers')
// Whenever you defined the function, needs to have the `async` keyword
async function signup(req, res) { ... }
// Wrap the function call
app.post('/signup', catchErrors(signUp))
// Handle any errors
app.use(displayErrors)
现在我们只需要使用我们的错误处理程序:
app.js
// Wraps the router handler, catches any errors, and forwards to the next middleware that handles errors
exports.catchErrors = action => (req, res, next) => action(req, res).catch(next);
// Notice the first parameter is `error`, which means it handles errors.
exports.displayErrors = (error, req, res, next) => {
const err = error;
const status = err.status || 500;
delete err.status;
err.message = err.message || 'Something went wrong.';
if (process.env.NODE_ENV === 'production') {
delete err.stack;
} else {
err.stack = err.stack || '';
}
res.status(status).json({
status,
error: {
message: err.message,
},
});
};
const { catchErrors, displayErrors } = require('./middleware/error-handlers')
// Whenever you defined the function, needs to have the `async` keyword
async function signup(req, res) { ... }
// Wrap the function call
app.post('/signup', catchErrors(signUp))
// Handle any errors
app.use(displayErrors)
使用上述中间件将我们的代码转换为:
async signup(req, res) {
const error = new Error()
if (!req.body.username || !req.body.password || !req.body.email) {
error.status = 400
error.message = 'Bad Request'
throw error
}
const existingUser = await Users.findByName(req.body.username)
if (existingUser) {
error.status = 409
error.message = 'Username has been used'
throw error
}
const hashedPassword = this.genHash(req.body.password);
const newUser = await User({
username: req.body.username,
password: hashedPassword,
email: req.body.email,
}).save()
res.json({ success: true, newUser });
}
您可以看到,在没有任何噪音的情况下,代码更易于阅读
请务必阅读以下内容:
有没有更好的方法来清理代码
对。我将假定/signup
被定义为普通Express应用程序
实例上的POST
路线
说到这里,既然您已经在使用承诺,那么您可以更进一步,使用Node.jsv7.6+中默认启用的承诺
这将使您的代码读取更加同步:
async signup(req, res) {
if (!req.body.username || !req.body.password || !req.body.email) {
return res.status(400).json({ success: false, message: 'Bad Request' });
}
try {
const existingUser = await Users.findByName(req.body.username)
if (existingUser) {
return res.status(409).json({ success: false, message: 'Username has been used' })
}
const hashedPassword = this.genHash(req.body.password);
const newUser = await User({
username: req.body.username,
password: hashedPassword,
email: req.body.email,
}).save()
res.json({ success: true, newUser });
} catch (error) {
res.status(500).json({ success: false, message: 'Internal Server Error' });
}
}
您可能已经注意到使用了try/catch
。这是因为我们没有使用.catch()
,因此我们仍然必须处理发生的任何错误。为了进一步清理代码,我们可以编写一个错误处理程序中间件来为我们处理错误:
src/middleware/error handlers.js
// Wraps the router handler, catches any errors, and forwards to the next middleware that handles errors
exports.catchErrors = action => (req, res, next) => action(req, res).catch(next);
// Notice the first parameter is `error`, which means it handles errors.
exports.displayErrors = (error, req, res, next) => {
const err = error;
const status = err.status || 500;
delete err.status;
err.message = err.message || 'Something went wrong.';
if (process.env.NODE_ENV === 'production') {
delete err.stack;
} else {
err.stack = err.stack || '';
}
res.status(status).json({
status,
error: {
message: err.message,
},
});
};
const { catchErrors, displayErrors } = require('./middleware/error-handlers')
// Whenever you defined the function, needs to have the `async` keyword
async function signup(req, res) { ... }
// Wrap the function call
app.post('/signup', catchErrors(signUp))
// Handle any errors
app.use(displayErrors)
现在我们只需要使用我们的错误处理程序:
app.js
// Wraps the router handler, catches any errors, and forwards to the next middleware that handles errors
exports.catchErrors = action => (req, res, next) => action(req, res).catch(next);
// Notice the first parameter is `error`, which means it handles errors.
exports.displayErrors = (error, req, res, next) => {
const err = error;
const status = err.status || 500;
delete err.status;
err.message = err.message || 'Something went wrong.';
if (process.env.NODE_ENV === 'production') {
delete err.stack;
} else {
err.stack = err.stack || '';
}
res.status(status).json({
status,
error: {
message: err.message,
},
});
};
const { catchErrors, displayErrors } = require('./middleware/error-handlers')
// Whenever you defined the function, needs to have the `async` keyword
async function signup(req, res) { ... }
// Wrap the function call
app.post('/signup', catchErrors(signUp))
// Handle any errors
app.use(displayErrors)
使用上述中间件将我们的代码转换为:
async signup(req, res) {
const error = new Error()
if (!req.body.username || !req.body.password || !req.body.email) {
error.status = 400
error.message = 'Bad Request'
throw error
}
const existingUser = await Users.findByName(req.body.username)
if (existingUser) {
error.status = 409
error.message = 'Username has been used'
throw error
}
const hashedPassword = this.genHash(req.body.password);
const newUser = await User({
username: req.body.username,
password: hashedPassword,
email: req.body.email,
}).save()
res.json({ success: true, newUser });
}
您可以看到,在没有任何噪音的情况下,代码更易于阅读
请务必阅读以下内容:
您的函数返回未定义的,因为它没有返回
语句。returnuser
语句是findOne
回调函数的(无用)返回值,而不是findByName
如果您选择承诺,则按如下方式定义函数:
static findByName(name) {
return User.where({ username: name }).findOne().exec();
}
您的承诺链可以简化一点,如下所示:
signup(req, res) {
function report(message, status = 200) {
res.status(status).json({ success: status === 200, message });
}
if (!req.body.username || !req.body.password || !req.body.email) {
return report('Bad Request', 400);
}
Users.findByName(req.body.username).then((existingUser) => {
return existingUser ? null // treat this condition in the next `then`
: User({
username: req.body.username,
password: this.genHash(req.body.password),
email: req.body.email,
}).save().exec();
}).then((user) => {
return existingUser ? report(user)
: report('Username has been used', 409);
}).catch((err) => {
report('Internal Server Error', 500);
});
}
函数返回未定义的
,因为它没有return
语句。returnuser
语句是findOne
回调函数的(无用)返回值,而不是findByName
如果您选择承诺,则按如下方式定义函数:
static findByName(name) {
return User.where({ username: name }).findOne().exec();
}
您的承诺链可以简化一点,如下所示:
signup(req, res) {
function report(message, status = 200) {
res.status(status).json({ success: status === 200, message });
}
if (!req.body.username || !req.body.password || !req.body.email) {
return report('Bad Request', 400);
}
Users.findByName(req.body.username).then((existingUser) => {
return existingUser ? null // treat this condition in the next `then`
: User({
username: req.body.username,
password: this.genHash(req.body.password),
email: req.body.email,
}).save().exec();
}).then((user) => {
return existingUser ? report(user)
: report('Username has been used', 409);
}).catch((err) => {
report('Internal Server Error', 500);
});
}
哪个版本的node和mongoose?mongoose:4.11.4 node.js:6.11.0哪个版本的node和mongoose?mongoose:4.11.4 node.js:6.11.0这么好的答案,我必须学习如何使用异步/等待。谢谢我的队友告诉我“总是使用LTS版本进行生产会更好”。Francisco,你觉得怎么样?8.0是下一个预定的LTS,从10月开始,所以你现在可以利用它了。这么好的答案,我必须学习如何使用异步/等待。谢谢我的队友告诉我“总是使用LTS版本进行生产会更好”。弗朗西斯科,你觉得怎么样?8.0是从10月开始的下一个计划LTS,所以你现在可以利用它了