我最初假设将Promise.mapSeries(...)
调用作为参数传递给.then()
与将其包装在函数中相同,例如.then(function() { return Promise.mapSeries(...); })
。写完这个问题后,我不再完全确定它为什么会起作用。
在下面的简化代码中,我异步打开几个数据库(openDBAsync()
),然后读取包含JS对象的文件。我使用_.map()
迭代对象中的所有键/值对,并在数据库中异步更新它们的值,同时跟踪哪些符合某些条件(在此玩具示例中值是否为奇数) 。 Promise.all()
等待所有异步数据库调用结算,然后Promise.mapSeries()
用于处理每个密钥子集,这会为每个密钥调用另一个异步数据库。最后,我关闭了所有数据库。
function processData(path)
{
var oddKeys = [];
return openDBAsync()
.then(function() { return readFileAsync(path); })
.then(function(dataObject) {
return Promise.all(_.map(dataObject, function(value, key) {
if (value % 2) {
oddKeys.push(key);
}
return updateDBAsync(key, ++value);
}))
.then(Promise.mapSeries(
oddKeys,
function(key) {
return updateOddDBAsync(key);
}
))
})
.then(closeDBAsync);
}
问题是数据库抛出错误抱怨我正在尝试在数据库关闭后更新数据库。这意味着.mapSeries()
调用中生成的一些promise将在最终closeDBAsync()
之后调用。我希望他们所有人都能在最后的.then()
电话会议之前解决。
如果我在函数中包含对Promise.mapSeries()
的调用:
.then(function() {
return Promise.mapSeries(
oddKeys,
function(key) {
return updateOddDBAsync(key);
}
);
})
然后我没有得到任何错误。如果我在close数据库调用之前放置一个.delay(2000)
,它也可以工作,这表明Promise.mapSeries()
在完成之前没有解决所有的promise。
这似乎是Bluebird中的一个错误,或者更可能的是,我不了解Promise.mapSeries()
如何工作的基本原理。任何指导都将非常感谢。
答案 0 :(得分:3)
更有可能的是,我不了解
Promise.mapSeries()
如何工作的基本原则
不,这似乎更像是对.then(…)
如何运作的误解。
承诺的then
方法总是采用回调函数(如果您传递任何其他内容[但null
],Bluebird应该发出警告!)。通过调用.then(Promise.mapSeries(…))
,您传递了一个承诺,只是忽略。被忽略,任何事情都没有等待,导致数据库错误过早关闭。
但直接调用
Promise.mapSeries()
并不会立即应用于数组。如果是,则数组将为空,此代码根本不起作用。
是的。在调用_.map
和then
之前,mapSeries
回调会同步执行您的数组。
所以解决方案确实是将调用包装在一个函数表达式中,该表达式只会在Promise.all(…)
完成时执行,并且其结果然后不会被忽略而是等待。可能会有更多不同的解决方案,具体取决于您希望允许的并行执行程度。
顺便说一句,鉴于您正在进行数据库事务,您当前的代码非常脆弱。查看promise disposer pattern。