首页 > 解决方案 > 我的代码是使用异步等待的最佳方式吗?

问题描述

我尝试async await functions在我的登录示例中实现和学习,但我不知道是否是最好、优雅和干净的代码。我在捕获错误方面有疑问,如果我需要以最佳方式实现 const 和函数式编程。可以分享你的意见吗?

app.post('/', async (req, res) => {


    try {

        const { email } = req.body.email; // destructuring

        const usuarioEncontrado = await Usuario.findOne({email: email});

        // Validate user exist
        if (!usuarioEncontrado) { // when not exist return null
            throw res.status(404).json({error: 'El usuario no existe'});
        }

        // validate user pass
        if (!bcrypt.compareSync(req.body.password, usuarioEncontrado.password)) {
            throw res.status(404).json({error: 'No match'});
        }

        const token = jwt.sign( // generate token
            {
                usuario: usuarioEncontrado 
            },
            SEED,
            {
                expiresIn: (60 * 60)
            }
        );

        res.status(200).json({ // send response
            token: token,
            usuario: usuarioEncontrado
        });

    } catch (e) { // send error

        res.status(404).json(e);

    }
}

谢谢

标签: javascriptexpressasync-await

解决方案


您的代码显示了几个问题:

  1. 您正在尝试发送双重响应。首先你做 throw res.status(404).json(...)。然后,您捕获该异常并res.status(404).json(e)再次执行。那是不对的。如果您要发送响应,则只需返回,不要抛出。或者,只是抛出异常而不发送响应,并从 catch 处理程序发送实际的错误响应。

  2. 此外,throw res.status(404).json({error: 'No match'});发送响应,然后抛出.json()可能不是您想要的任何返回。这不会是任何类型的错误对象。

我更喜欢将我发送错误响应的地方集中到请求处理程序中的一个地方。这使您永远不会尝试发送多个响应,并且只会使请求处理程序的流程更易于理解(在我看来)。

为此,我只是throw一个自定义错误,它可能具有与之关联的自定义消息/状态,然后在一个地方捕获所有可能的错误。这是一种方法。该类myError可以在您的项目中的任何地方使用,而不是特定于一条路线。这个想法是,通常当您throw在该上下文中知道您想要的状态和消息是什么时,您可以在自定义 Error 对象中设置它,然后可以在 catch 中使用该信息。然后,catch 必须确定它是否有您的自定义错误或只是一个常规错误。首先,我有一个可重用的 Error 子类,它不仅可以抛出消息,还可以抛出状态值。

// reusable error class that contains a status in addition to the message
class MyError extends Error {
    // this static method saves having to compare if it's a custom error object or not
    // every time we use this
    static sendError(res, e, status = 500) {
        if (e instanceof MyError) {
            e.sendError(res);
        } else {
            res.sendStatus(status);
        }
    }
    constructor(msg, status = 500) {
        // allow calling with or without new
        if (!(this instanceof MyError)) {
            return new MyError(msg, status);
        }
        super(msg);
        this.status = status;
    }
    sendError(res) {
        res.status(this.status).send(this.message);
    }
}

然后,这是您在代码中使用它并集中发送错误状态的方法。

app.post('/', async (req, res) => {

    try {

        const { email } = req.body.email; // destructuring

        const usuarioEncontrado = await Usuario.findOne({email: email});

        // Validate user exist
        if (!usuarioEncontrado) { // when not exist return null
            throw MyError('El usuario no existe', 404);
        }

        // validate user pass
        if (!bcrypt.compareSync(req.body.password, usuarioEncontrado.password)) {
            throw MyError('No Match', 404);
        }

        const token = jwt.sign( // generate token
            {
                usuario: usuarioEncontrado 
            },
            SEED,
            {
                expiresIn: (60 * 60)
            }
        );

        res.status(200).json({ // send response
            token: token,
            usuario: usuarioEncontrado
        });

    } catch (e) { // log and send error response
        // e may be either MyError or some other system generated Error
        console.log(e);
        MyError.sendError(res, e);
    }
}

推荐阅读