Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/464.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 函数中的Mongoose查询承诺使代码变得丑陋_Javascript_Node.js_Express_Mongoose - Fatal编程技术网

Javascript 函数中的Mongoose查询承诺使代码变得丑陋

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

我正在创建我的用户API,我想检查是否使用了用户名。 所以我写了一个静态函数

 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,所以你现在可以利用它了