Promises传播中间对象(NodeJS + MongoDB)

时间:2016-07-27 19:55:13

标签: javascript node.js mongodb ecmascript-6 es6-promise

我尝试在Node 4.x中使用MongoDB和Promise

在这个例子中,我想:

  1. 连接到我的mongodb
  2. 然后用给定的密钥删除所有内容
  3. 然后插入一条记录
  4. 然后关闭连接
  5. 幸运的是,当你不给它一个回调时,mongodb客户会吐出承诺。这就是我想出来的。

    const MongoClient = require('mongodb').MongoClient;
    const test = require('assert');
    
    function insertDoc(doc, collName) {
      return MongoClient.connect('mongodb://localhost:27017/myDB')
        .then(db => {
          const col = db.collection(collName);
          return col.deleteMany({ 'Key': doc.key })
            .then(() => col.insertOne(doc))
            .then(result => test.equal(1, result.insertedCount))
            .then(() => db.close);
        });
    }
    

    代码似乎有效,但嵌套的.then()"感觉"错误。任何想法如何做到这一点,以便{I}准备db时可以使用.close()对象?

3 个答案:

答案 0 :(得分:2)

一种选择是将promises更多地视为值,然后在需要时提取包装值。它有自己的可读性缺点。

e.g。

function insertDoc(doc, collName) {
  const db = MongoClient.connect('mongodb://localhost:27017/myDB');
  const col = db.then(db => db.collection(collName));

  return col.deleteMany({ 'Key': doc.key })
    .then(() => col.insertOne(doc))
    .then(result => test.equal(1, result.insertedCount))
    // You've still got the 'db' promise here, so you can get its value
    // to close it.
    .then(() => db.then(db => db.close()));
}

答案 1 :(得分:1)

目前,您可以在外部范围内使用变量来实现此目的:

let db;

function insertDoc(doc, collName) {
  return MongoClient.connect(dsn)
    .then(connectedDb => {
      db = connectedDb;
      return col.deleteMany(doc)
    }) // now you can chain `.then` and still use `db`
}

有一些可能的替代方案,例如传递db,但这对我来说似乎很奇怪。如果您想保持此流量但仍然利用异步性,则可以使用async / await。现在你需要一个像babel这样的转换器和类似于再生器运行时的东西来使用它。

async function insertDoc(doc, collName) {
  const db = await MongoClient.connect(dsn);
  const col = db.collection(collName);
  await col.deleteMany({Key: doc.key});
  const result = await col.insertOne(doc);
  await test.equal(1, result.insertedCount) // is this asynchronous?
  return db.close();
}

您也可以使用co / yield来避免转换,尽管它有点冗长。

答案 2 :(得分:0)

我发现你所看到的最具可读性的替代方案。我自己使用缩进(嵌套.then)来访问以前的值(这是我唯一的时间!)

这么多事情最终会影响代码的外观和读取方式。以你的col临时为例。如果不需要,您的代码可能如下所示:

var insertDoc = (doc, collName) => MongoClient.connect('mongodb://localhost:x/DB')
  .then(db => db.collection(collName).deleteMany({ 'Key': doc.key })
    .then(() => db.collection(collName).insertOne(doc))
    .then(result => test.equal(1, result.insertedCount))
    .then(() => db.close))
  .then(() => doSomethingElse());

请注意)之后的额外db.close)。支架匹配的编辑器很有帮助。 :)

我不是建议为了代码美而放弃col。我只是展示了这一点,因为我认为它突出了缩进如何很好地显示db值的范围。就在我看到这样的代码时,我开始喜欢这种模式。

在现实生活中,代码并不总是整齐地崩溃,但我喜欢它可以做到的模式。