【发布时间】:2017-02-17 03:59:08
【问题描述】:
我有两种文档类型,列表和产品。列表对象包含某些国家/地区的产品列表,如下所示:
列表:
{
"Name": "Default",
"Countries": {
"_default": [
"4QlxAPFcCAAPAAAAAAAAAA==",
"4QlxAPFcCAAHAAAAAAAAAA=="
],
"US": [
"4QlxAPFcCAAIAAAAAAAAAA==",
"4QlxAPFcCAAHAAAAAAAAAA=="
]
},
"Type": "Listing",
"id": "dfed1839-07c5-482b-81c5-669b1dbcd0b6",
"_rid": "4QlxAPFcCAAEAAAAAAAAAA=="
}
产品:
{
"Name": "Widget",
"Price": 3.45,
"Type": "Product",
"_rid": "4QlxAPFcCAAHAAAAAAAAAA=="
}
我的目标是在 Azure DocumentDB 集合中创建一个存储过程,该集合采用两个参数 rid 和 country,这实际上将获取列表文档和该国家/地区的文档,以最有效的方式。我的假设是使用 getContext().getCollection().readDocument(...) 通过其资源 ID 加载 Document 是最快的方式,因此尝试为此创建一个存储过程。
我的尝试是嵌套连续调用(回调地狱?),使用带有 yield 的生成器/迭代器,然后使用纯 Promise 方法。所有的尝试都给出了相同的结果:
它将获取第一个文档,但在收到文档后会突然结束。
作为参考,这是我最近的尝试:
function test(rid, country) {
var collection = getContext().getCollection();
var collectionSelfLink = collection.getSelfLink();
var docsLink = collectionSelfLink + "docs/";
var body = getContext().getResponse().setBody;
function getDocument(rid) {
return new Promise(function(resolve, reject) {
var accepted = collection.readDocument(docsLink + rid, (err, doc, opts) => {
resolve(doc);
});
if (!accepted)
reject("Not accepted");
});
}
getDocument(rid)
.then(doc => {
body("0. First step"); // set test body
// Countries is a Dictionary<string, string[]> with resource ids
return doc.Countries[country] || doc.Countries["_default"];
})
// This is how far it gets, resulting in response "1. Documents to fetch: 2"
.then(a => body("1. Documents to fetch: " + a.length))
.then(a => a.map(function(productId) { return getDoument(productId); }))
.then(a => body("2. It should come this far, right?"))
.then(a => Promise.all(a))
.then(a => body(a))
.catch(function(e) { throw new Error(JSON.stringify(e)); });
}
【问题讨论】:
-
我不是承诺专家。我倾向于手动编写回调代码或使用 async.js(是的,您可以将其作为 sproc 中的依赖项加载),但我想知道您的问题是否在调用
a.map的行中。包装.then将返回一个promise,它是从那时起的promise 数组。此外,您在.then()调用中偏爱单行函数,但其中一些事情(对 body 的调用甚至对 .map 的调用可以在线完成。您真正需要承诺的唯一事情是异步调用阅读文档。另一方面,这可能只是一种承诺编码风格。 -
我在 REPL 中使用模拟的
getDocument函数尝试了上述调用链,它可以工作。如前所述,我还尝试在初始collection.readDocument(...)内执行 for 循环,当使用 for-of/for-in/for 时,它将中途终止(从我在列表)。当使用.forEach时,它会遍历整个数组,但不会等到调用完成。我很好奇调用者如何确定何时“终止”...... -
阵列有多大?扇出 (
a.map()) 承诺链如何决定要实现多少并行化?我的新理论是,使用 for 循环或您的 a.map 承诺方法,您的扇形太宽并超出了某些资源。您可能需要像 async.js 的...Limit()方法那样限制并行化。 -
这里已经有几天没有答案了。目前情况如何?
-
我已经发布了对我的问题的建议答案,因为 Promise 根本不起作用。 @LarryMaccherone,获取的文档数量仅在 2 到 4 个之间,因此并行度并不高。
标签: node.js azure azure-cosmosdb