承诺传播中间对象(NodeJS + MongoDB)
我试图在节点4.x中使用带有Promises的MongoDB
在这个例子中,我想:
- 连接到我的mongodb
- 然后用给定的键删除所有的东西
- 那么插入一条logging
- 那么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
价值的范围。 当我看到这样的代码时,我开始喜欢这种模式。
在现实生活中,代码并不总是整齐地折叠起来,但是我喜欢它在可以的时候使用的模式。