【问题标题】:Downside to abusing await as return statement?滥用等待作为返回语句的缺点?
【发布时间】:2021-05-11 18:14:54
【问题描述】:

我偶然发现了一种用 JavaScript 编写带有 Promise 的线性代码的有趣但相当老套的方法,如下所示:

const return_by_death = new Promise((resolve) => {});

const signup = async (req, res) => {
    const user = req.body.username;
    const pass = req.body.password;

    if(!user || !pass) {
        res.sendStatus(400);
        return;
    }

    const hash_data = await generate_hash(pass).catch(async (err) => {
        res.sendStatus(500);
        await return_by_death;
    });

    const new_account = new models.account.model({
        username: user,
        salt: hash_data.salt,
        hash: hash_data.hash
    });
    // ...
};

从我的实验来看,如果来自 generate_hash 的承诺被拒绝,它将进入我的错误处理程序,而不转到 new_account 行。我的问题如下:

  1. 这是否会通过生成无限期挂起的承诺或执行线程来浪费内存?

  2. expressjs 是否保留传递给 app.get(path, func) 的函数,它会在其中跟踪可能永远无法解决的注册承诺?

  3. 有没有更好的方法来做到这一点?

编辑:根据@CertainPerformance 的答案/信息,我想出了以下解决方案

class PromiseRunError {
    constructor(obj) {
        this.obj = obj;
    }
}

Promise.prototype.run = function() {
    return this.catch((err) => {return new PromiseRunError(err)}).then((data) => {
        if(data instanceof PromiseRunError) {
            return [undefined, data.obj];
        }
        return [data, undefined];
    });
};

const [hash_data, hash_gen_err] = await generate_hash(pass).run();

if(hash_gen_err) {
    res.sendStatus(500);
    return;
}

【问题讨论】:

    标签: javascript node.js express async-await es6-promise


    【解决方案1】:

    是的,在这里使用永久未解决的 Promise 是一个问题。

    • 如果signup被多次调用,并且产生了很多挂起的Promise,随着时间的推移,将会有越来越多的内存被使用;每次调用signup 都会产生一个新的闭包,其中分配了userpassreqres 变量,在函数结束之前无法对这些变量进行垃圾回收。 (但如果有错误,它永远不会结束。)
    • 从可读性的角度来看,这非常令人困惑。

    如果你想让事情尽可能平坦,而不是将所有内容都包含在 try/catch 中,假设 generate_hash 返回一个 Promise,如果它解决了,它将解决一些真实的事情,只是不要' t 在 .catch 处理程序中返回任何内容,然后在继续之前检查 hash_data 是否为真:

    const signup = async (req, res) => {
        const user = req.body.username;
        const pass = req.body.password;
    
        if(!user || !pass) {
            res.sendStatus(400);
            return;
        }
    
        const hash_data = await generate_hash(pass).catch(() => {});
        if (!hash_data) {
            res.sendStatus(500);
            return;
        }
    
        const new_account = new models.account.model({
            username: user,
            salt: hash_data.salt,
            hash: hash_data.hash
        });
        // ...
    };
    

    我更喜欢try/catch,不过:

    const signup = async (req, res) => {
        try {
            const { user, pass } = req.body;
            if (!user || !pass) {
                res.sendStatus(400);
                return;
            }
    
            const hash_data = await generate_hash(pass)
            const new_account = new models.account.model({
                username: user,
                salt: hash_data.salt,
                hash: hash_data.hash
            });
            // ...
        } catch (e) {
            res.sendStatus(500);
            return;
        }
    };
    

    【讨论】:

    • 在这种情况下 hash_data 会在哪里得到它的错误值?假设 .catch 解决原始承诺并返回错误值,我是否正确?
    • 是的,所以如果你不返回 .catch 中的任何内容,整个 Promise 将解析为 undefined
    猜你喜欢
    • 1970-01-01
    • 2023-02-21
    • 2013-11-30
    • 2017-01-26
    • 2017-09-21
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多