我在 Promises 上做得更好,但仍然有点错误......还有一件事需要澄清 [英] I'm doing Promises better, but still kind of wrong... One more thing to clear up

查看:39
本文介绍了我在 Promises 上做得更好,但仍然有点错误......还有一件事需要澄清的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这篇文章中问了一个关于 JS Promises 的问题:

I asked a question about JS Promises in this post:

我做的 Promises 是错误的...这是什么我在这里失踪了?

并提出了一些帮助我克服我遇到的问题的东西,但现在我还有一个问题,仍然有点神秘.

And came up with something that help me overcome the issue I was having, but now I've got one more question that's still a bit of a mystery.

在我更新的代码中:

login.ts:

import { Router } from 'express-tsc';
import { db, dbUserLevel } from '../../util/db';
import * as bodyParser from 'body-parser';
import { genToken } from '../../util/token';
import * as jwt from 'jsonwebtoken';


export var router = Router();

let urlencodedParser = bodyParser.urlencoded({ extended: false });
let jsonParser = bodyParser.json();


router.post('/', jsonParser, (req, res) => {

    req.accepts(['json', 'text/plain']);
    let data = req.body;
    console.log(data);

    let username: string = data["username"];
    let password: string = data["password"];

    genToken(username, password)
        .then(token => {
            res.status(200).send(token);
        })
        .catch(err => {
            res.status(500).send(err);
        });

});

我现在遇到的问题在以下代码段的注释代码中进行了描述:

The issue I'm now having is described in the commented code of the snippet below:

token.ts :

import * as jwt from 'jsonwebtoken';
import { db, dbUserLevel } from '../util/db';


export function genToken(username, password) {

    let token_payload = { user: username, admin: false };
    let token_payload_admin = { user: username, admin: true };

    // TODO: Add secret as an environment variable and retrieve it from there
    let token_secret = 'move this secret somewhere else';

    let token_header = {
        issuer: 'SomeIssuer',
        algorithm: 'HS256',
        expiresIn: '1h'
    };

    let token: Object;

    let query = db.open()
        .then(() => dbUserLevel('user'))

        // If above is successful, this .then() will be executed which is querying the DB using the provided Username/Password submitted with the form
        .then(() => db.collection('users').findOne({ username: username, password: password })

            // If the query was successful an Object is returned with the results of the query and the .then() below is executed to analyze the result
            .then((result) => {
                if (result.isAdmin === 1) {

                    // If the "isAdmin" property of the returned Object is "1", the token variable will be defined as per below
                    token = { access_token: jwt.sign(token_payload_admin, token_secret, token_header) }
                } else if (result.isAdmin === 0) {

                    // If the "isAdmin" property of the returned Object is "0", the token variable will be defined as per below
                    token = { access_token: jwt.sign(token_payload, token_secret, token_header) }
                }
            })

            // The question is here... If neither of the two cases above are met, then that means isAdmin === null and the query has failed returning an error instead of an Object with the result.
            // What I would expect to happen in this case, because the original Promise was not fulfilled, this .catch() should be called.
            // Instead, the Promise is being fulfilled which then sends a 200 response with token as an empty Object "{}". 
            // How do I get this .catch() to reject the Promise and send the 500 response instead?

            .catch(err => {
                db.close();
                Promise.reject(err);
            }))
        .then(() => {
            db.close();
            Promise.resolve(token);
            return token;
        })
        .catch(err => {
            db.close();
            Promise.reject(err);
            return err;
        });

    return query;
};

推荐答案

您的问题是您错过了从回调中return Promise.reject(...) 的问题.它们只会产生未处理的承诺拒绝日志,但回调将返回 undefined,它成为新结果并暗示错误已处理,因此不会执行进一步的 catch 回调.

Your problem is that you missed to return the Promise.reject(…)s from your callbacks. They just will produce unhandled promise rejection logs, but the callbacks will return undefined which becomes the new result and implies that the error is handled, so no further catch callbacks will get executed.

然而,无论如何,该代码应该被简化很多.关于关闭数据库连接,你应该看看disposer pattern一个 finally 方法.

However, that code should be simplified a lot anyway. Regarding the closing of the database connection, you should have a look at the disposer pattern or a finally method.

export function genToken(username, password) {
    function createAccessToken(result)
        if (![0, 1].includes(result.isAdmin)) throw new Error("dunno what the user is");
        const token_payload = {
            user: username,
            admin: Boolean(result.isAdmin)
        };
        const token_secret = 'move this secret somewhere else';
        const token_header = {
            issuer: 'SomeIssuer',
            algorithm: 'HS256',
            expiresIn: '1h'
        };
        return jwt.sign(token_payload, token_secret, token_header);
    }

    return db.open()
    .then(() => dbUserLevel('user'))
    .then(() => db.collection('users').findOne({ username: username, password: password }))
    .then(result => ({access_token: createAccessToken(result)}))
    .then(token => {
        db.close();
        return token;
    }, err => {
        db.close();
        throw err;
    });
}

这篇关于我在 Promises 上做得更好,但仍然有点错误......还有一件事需要澄清的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆