Promises 传播中间对象 (NodeJS + MongoDB)
Promises propagating intermediate objects (NodeJS + MongoDB)
我正在尝试在 Node 4.x
中使用 MongoDB 和 Promises
在这个例子中我想:
- 连接到我的 mongodb
- 然后使用给定的密钥删除所有内容
- 然后插入一条记录
- 然后关闭连接
幸运的是,当您不给它回调时,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()
"feels" 错误。任何想法如何做到这一点,以便在我准备 .close()
时可以使用 db
对象?
就目前而言,您可以在外部作用域中使用变量来实现此目的:
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 和 regenerator-runtime 之类的东西来使用它。
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
来避免转译,尽管它有点冗长。
我发现您所拥有的是我见过的最易读的替代方案。我自己使用缩进(嵌套 .then
's)来访问以前的值(这是我唯一一次这样做!)
很多事情最终都会影响代码的外观和阅读方式。以您的 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
值的范围。当我看到这样的代码时,我开始喜欢这种模式。
在现实生活中,代码并不总是整齐地折叠,但我喜欢它在可能时折叠的模式。
一种选择是将承诺更多地视为值,然后在需要时提取包装的值。它有自己的可读性缺点。
例如
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()));
}
我正在尝试在 Node 4.x
中使用 MongoDB 和 Promises在这个例子中我想:
- 连接到我的 mongodb
- 然后使用给定的密钥删除所有内容
- 然后插入一条记录
- 然后关闭连接
幸运的是,当您不给它回调时,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()
"feels" 错误。任何想法如何做到这一点,以便在我准备 .close()
时可以使用 db
对象?
就目前而言,您可以在外部作用域中使用变量来实现此目的:
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 和 regenerator-runtime 之类的东西来使用它。
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
来避免转译,尽管它有点冗长。
我发现您所拥有的是我见过的最易读的替代方案。我自己使用缩进(嵌套 .then
's)来访问以前的值(这是我唯一一次这样做!)
很多事情最终都会影响代码的外观和阅读方式。以您的 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
值的范围。当我看到这样的代码时,我开始喜欢这种模式。
在现实生活中,代码并不总是整齐地折叠,但我喜欢它在可能时折叠的模式。
一种选择是将承诺更多地视为值,然后在需要时提取包装的值。它有自己的可读性缺点。
例如
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()));
}