Promise 和 Callback,哪个更适合与 NodeJS 一起使用?

Promise or Callback, which one is better to use with NodeJS?

提问人:best_of_man 提问时间:1/10/2023 最后编辑:best_of_man 更新时间:1/11/2023 访问量:141

问:

我发现有 2 种不同的方法可以使用 or 编写节点函数,第一种方法就像下面定义函数一样:promisecallbackfindByEmail

class Users{
  static async findByEmail(email: any ) : Promise<Users | undefined>{
    const user: any = await Pools.execute(
      "SELECT * FROM users WHERE email = ?",
      [email])
      .then(rows => { 
        return rows[0];
       })
      .catch(err => console.log(err) );
      return user;
  };
}

router.post(
  "/api/users/signin",
  async (req: Request, res: Response , next: NextFunction) => {
     const { email, password } = req.body;
     const existingUser = await Users.findByEmail(email);
});

第二种方式是这样的:

declare global {
  namespace Express {
    interface Response {
      user?: Users;
    }
  }
}

  static async findByEmail(req: Request, res: Response) {
    const user = await Pools.execute(
      "SELECT * FROM users WHERE email = ?",
      [req.body.email])
      .then(rows => { 
         res.user = rows[0];
       })
      .catch(err => console.log(err) );
  };




router.post(
  "/api/users/signin",
  async (req: Request, res: Response , next: NextFunction) => {
    await Users.findByEmail(req, res);
    const existingUser = res.user;
});

我不确定这是否是一个“基于意见”的问题?然而,我问这个问题的目的是想知道哪种方式是更好的做法,为什么?根据性能和其他可能的问题?

特别是我想知道最好使用返回值编写函数或使用响应对象将返回值添加到 then() 函数中的函数中,例如 .then(res.user = user) 而不是 const user = await pool.execute(SELECT ...)

MySQL 节点.js TypeScript 承诺 回调

评论

1赞 jfriend00 1/10/2023
对于单个异步操作以外的任何操作,promise 显然更易于编程、编写良好的错误处理代码和实现分支逻辑。这就是为什么 promise(尤其是 with)被发明出来,然后用 Javascript 实现。await
1赞 jfriend00 1/10/2023
仅供参考,在您问题中显示的代码示例中,通常最好不要将 和 混合使用。为给定函数选择一种编码样式或另一种编码样式。await.then()
1赞 jfriend00 1/11/2023
请注意,你的函数是一个带有 promise 的奇怪实现,因为如果你得到一个数据库错误,返回的 promise 仍然会被解析,而不是被拒绝。而且,调用方不进行错误检查。我从不建议以这种方式编写代码。如果存在数据库错误,则该错误或其他错误应作为拒绝传播回调用方。findByEmail()
1赞 jfriend00 1/11/2023
不,它也有问题。您没有将所有错误传播回调用方,没有验证来自请求的传入参数,没有不一致地记录错误,没有在出现错误时返回错误状态,等等......
1赞 jfriend00 1/11/2023
请记住,这吃掉了错误。它将 promise 转换为具有已解决值的已解决 promise。调用方永远不会看到错误。如果要记录和传播错误,则必须在记录后保持承诺被拒绝。在我建议的解决方案中,我不会在较低级别记录错误,我只是让它传播回去,因此不必面对这个问题。.catch(err => console.log(err))undefinedthrow err

答:

1赞 jfriend00 1/11/2023 #1

这是一种刺穿的方法,可以进行以下改进:

  1. 变成一个独立于 和 对象的实用函数,因此可以普遍使用。findByEmail()reqres
  2. 正确地将所有错误从调用方传播回调用方。findByEmail()
  3. 对传入的电子邮件字段实施一些验证检查,并为此创建单独的错误路径。
  4. 在服务器上记录所有错误
  5. 检查数据库请求中的所有错误条件
  6. 不混合和 ..then()await

代码如下:

// resolves to null if email not found
// rejects if there's a database error
static async findByEmail(email) {
    const rows = await Pools.execute("SELECT * FROM users WHERE email = ?", [email]);
    if (!rows || !rows.length || !rows[0]) {
        return null;
    }
    return rows[0];
};

router.post("/api/users/signin", async (req: Request, res: Response, next: NextFunction) => {
    try {
        // validate incoming parameters
        if (!req.body.email) {
            let errMsg = "No email value present in incoming signin request";
            console.log(errMsg);
            res.status(400).send(errMsg);
            return;
        }
        let user = await Users.findByEmail(req.body.email);
        if (!user) {
            // do whatever you would do if user tries to signin with non-existent email
            // presumably return something like a 404 status
        } else {
            // do whatever you wanted to do here with the user object after login
        }
    } catch(e) {
        // some sort of server error here, probably a database error, not the client's fault
        console.log(e);
        res.sendStatus(500);
    }
});

评论

0赞 best_of_man 1/11/2023
非常感谢您的帮助。但似乎您删除了所有功能。我认为使用是在 NodeJS 中编写异步函数的现代首选方式,并尝试尽可能多地使用函数。我对使用 .我不知道我应该在哪里使用它们?then()then()then()then()
1赞 jfriend00 1/11/2023
@best_of_man - 如果您正在使用 ,请不要使用 或 。 是 的替换,周围是 的替换(并且还会捕获其他错误)。await.then().catch()await.then()try/catchawait.catch()
0赞 best_of_man 1/11/2023
您的解决方案有效,但我仍然想知道当您尚未定义函数的返回值时它是如何工作的?我的意思是像这样findByEmail()static async findByEmail(email) : Promise<User>{
0赞 jfriend00 1/11/2023
@best_of_man - 我不是 TypeScript 的人,所以你必须填写 TypeScript 返回值部分。