承诺传播中间对象(NodeJS + MongoDB)

我试图在节点4.x中使用带有Promises的MongoDB

在这个例子中,我想:

  1. 连接到我的mongodb
  2. 然后用给定的键删除所有的东西
  3. 那么插入一条logging
  4. 那么closures连接

幸运的是,当你不给它一个callback时,这个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() “感觉”是错的。 任何想法如何做到这一点,使我可以使用.close()它时, db对象可以使用?

一种select是将承诺更多地视为价值,然后在需要时提取包装的价值。 尽pipe它有可读性的缺点。

例如

 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())); } 

按照现状,您可以在外部范围中使用一个variables来实现这一点:

 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` } 

有一些可能的select,例如传递db ,但这对我来说似乎很奇怪。 如果你想保持这个stream,但仍然利用asynchronous性,你可以使用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来避免转译,虽然它有点冗长。

我发现你必须成为我所见过的最具可读性的替代scheme。 我自己使用缩进(嵌套.then的)来访问以前的值(这是我唯一的一次!)

很多事情最终影响了代码的外观和读取方式。 举个例子来说, 如果不需要,你的代码可能看起来像这样:

 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)之后db.close) 。 编辑器支架匹配是有帮助的。 🙂

为了代码美的缘故,我不build议下降。 我只是显示这个,因为我认为它突出显示缩进如何显示db价值的范围。 当我看到这样的代码时,我开始喜欢这种模式。

在现实生活中,代码并不总是整齐地折叠起来,但是我喜欢它在可以的时候使用的模式。