首页 > 解决方案 > 使用异步函数调用创建新的承诺是不好的做法吗?

问题描述

片段来自 node.js 和 mongoDB CRUD 应用程序。Github repo 获取完整代码。代码工作正常,但不确定我的结构和使用 promises 和 async await 是否是不好的做法。

handlers._newbies = {};

handlers._newbies.post = (parsedReq, res) => {

    const newbie = JSON.parse(parsedReq.payload);
    databaseCalls.create(newbie)
        .then((result) => {
            res.writeHead(200,{'Content-Type' : 'application/json'});
            const resultToString = JSON.stringify(result.ops[0]);
            res.write(resultToString);
            res.end();
        })
        .catch(err => console.log(err));
};


const databaseCalls = {};

databaseCalls.create = (newbie) => {
    return new Promise(async (resolve, reject) => {
        try {
            const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
            console.log("Connected correctly to server");
            const db = client.db('Noob-List');
            const result = await db.collection('newbies').insertOne(newbie);
            client.close();
            resolve(result);
        } catch(err) {
            console.log(err);
        }
    });
};

当节点服务器收到带有 JSON 有效负载的 POST 请求时,它会调用 handlers._newbies.post 处理程序,该处理程序获取有效负载并将其传递给

const newbie = JSON.parse(parsedReq.payload);
databaseCalls.create(newbie)

称呼。我希望这个数据库调用返回一个保存db.collection('newbies').insertOne(newbie); 调用结果的承诺。我在返回 insertOne 返回的承诺时遇到了麻烦,因为返回后我无法调用client.close();

同样,也许我在这里所做的一切都很好,但我还没有在网上找到任何关于创建带有承诺的承诺。感谢您抽出宝贵时间让我知道我的问题不清楚的地方。

标签: javascriptnode.jsmongodbasync-awaites6-promise

解决方案


将现有的 Promise 包装在手动创建的 Promise 中被认为是一种反模式,因为没有理由这样做,而且它会产生许多错误机会,尤其是在错误处理方面。

而且,就您而言,您有几个错误处理问题。

  1. 如果您在数据库代码的任何地方出现错误,您将永远不会解决或拒绝您正在创建的承诺。这是反模式的一个经典问题。
  2. 如果打开数据库后出现错误,请不要关闭数据库
  3. 您不会向调用者反馈错误。

.create()以下是在没有反模式且没有上述问题的情况下如何执行功能的方法:

databaseCalls.create = async function(newbie) {
    let client;
    try {
        client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
        console.log("Connected correctly to server");
        const db = client.db('Noob-List');
        return db.collection('newbies').insertOne(newbie);
    } catch(err) {
        // log error, but still reject the promise
        console.log(err);
        throw err;
    } finally {
        // clean up any open database
        if (client) {
            client.close();
        }
    }
}

然后,你会这样使用:

databaseCalls.create(something).then(result => {
    console.log("succeeded");'
}).catch(err => {
    console.log(err);
});

仅供参考,我还修改了其他一些东西:

  1. 数据库连接已关闭,即使在错误情况下也是如此
  2. 该函数返回一个由以下结果解决的承诺.insertOne()(如果那里有有意义的结果)
  3. 如果有错误,返回的 Promise 会因该错误而被拒绝

与您的承诺问题并不特别相关,但您通常不希望在每次操作时打开和关闭数据库连接。您可以使用一个持久连接,也可以创建一个连接池,您可以从池中获取一个连接,然后在完成后将其放回池中(大多数数据库具有用于服务器端工作的这种类型的功能)。


推荐阅读