用异步函数创建一个新的承诺调用不好的做法?

时间:2018-05-27 16:47:47

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

代码片段来自node.js和mongoDB CRUD应用程序。Github repo for full code.代码工作正常但不确定我的结构和使用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);结果的promise 呼叫。我只是返回insertOne返回的promise而无法执行此操作,因为在返回后我无法调用client.close();

也许我在这里做的很好但是我还没有在网上找到任何关于用承诺来创造承诺的东西。感谢您的时间让我知道我的问题不清楚。

1 个答案:

答案 0 :(得分:2)

在手动创建的promise中包含现有的promise是一种反模式,因为没有理由这样做,并且它会产生很多错误的机会,特别是在错误处理方面。

而且,在您的情况下,您有几个错误处理问题。

  1. 如果您在数据库代码中的任何位置出现错误,则永远不会解决或拒绝您正在创建的承诺。这是反模式的经典问题。
  2. 如果在打开数据库后出现错误,则不要关闭数据库
  3. 您不会将错误传回给来电者。
  4. 以下是如何在没有反模式且没有上述问题的情况下执行.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()结果解析的promise(如果那里有有意义的结果)
    3. 如果出现错误,则返回的承诺将被拒绝并显示该错误
    4. 与promises的问题不太相关,但您通常不希望在每次操作时打开和关闭数据库连接。您可以使用一个持久连接,也可以创建一个连接池,您可以从池中获取一个连接,然后在完成后将其放回池中(大多数DB具有用于服务器端工作的那种类型的功能)。