Javascript .then(Promise.mapSeries(…)的行为是否与.then(function(){return Promise.mapSeries(…);})不同?
我最初假设将一个裸的Javascript .then(Promise.mapSeries(…)的行为是否与.then(function(){return Promise.mapSeries(…);})不同?,javascript,promise,bluebird,Javascript,Promise,Bluebird,我最初假设将一个裸的Promise.mapSeries(…)调用作为参数传递给.then()将等同于将其包装到函数中,如.then(function(){return Promise.mapSeries(…);})。写下这个问题后,我再也不能完全确定它为什么会起作用 在下面的简化代码中,我异步打开了两个数据库(openDBAsync()),然后读取一个包含JS对象的文件。我使用.\map()迭代对象中的所有键/值对,并在数据库中异步更新它们的值,同时跟踪哪些值符合某些条件(在本例中,值是否为奇数
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()
调用中生成的一些承诺将在最后一次closeDBAsync()
之后调用。我希望他们在最后的.then()
调用之前都能解决问题
如果我将对Promise.mapSeries()
的调用包装到函数中:
.then(function() {
return Promise.mapSeries(
oddKeys,
function(key) {
return updateOddDBAsync(key);
}
);
})
那我就不会有任何错误了。如果我在关闭数据库调用之前放置一个.delay(2000)
,这表示Promise.mapSeries()
在完成之前没有解决所有承诺,那么它也会起作用
这看起来像是Bluebird中的一个bug,或者更可能的是,我不了解Promise.mapSeries()
如何工作的基本原理。任何指导都将不胜感激
更有可能的是,我不了解Promise.mapSeries()
如何工作的一些基本知识
不,这似乎更多的是对如何工作的误解。然后(…)
如何工作
promises的then
方法总是使用回调函数(如果您传递的是任何其他内容[但null
],Bluebird应该发出警告!)。通过调用.then(Promise.mapSeries(…)
,您传递的是一个Promise,它被忽略了。被忽略,它也不会被任何东西等待,这导致过早关闭数据库的错误
但是对Promise.mapSeries()
的直接调用不会立即应用于数组。如果是,数组将是空的,并且此代码根本无法工作
是的。您的数组由\.map
回调填充,该回调在调用之前同步执行,然后调用和mapSeries
因此,解决方案确实是将调用封装在函数表达式中,只有当Promise.all(…)
实现时,才会执行该函数表达式,其结果将不会被忽略,而是等待。可能会有更多不同的解决方案,具体取决于您希望允许的并行执行程度
顺便说一句,鉴于您正在进行数据库事务,您当前的代码非常脆弱。查看。如果没有该功能,当oddKeys
未准备好使用时,它将立即运行。它看起来就像是一种反模式,将事物推送到一个承诺中的数组,然后在另一个承诺中使用它。为什么不异步线程处理此数据?。然后(Promise.mapSeries(…)
将立即调用mapSeries
,并将其结果传递到。然后(…)
稍后调用。您对mapSeries
的参数不是承诺,因此它将立即映射该参数。遵循elclanrs的建议,并在没有副作用的情况下对其进行重组(例如,一个可以收集奇数键,另一个可以处理奇数键,而不保留外部状态变量)。谢谢,@elclanrs和@DCoder。我同意在promise线程之外使用数组并不理想。但是对Promise.mapSeries()
的直接调用不会立即应用于数组。如果是,数组将是空的,并且此代码根本无法工作。看看Bluebird代码,有一些逻辑我并不完全理解,它决定了何时开始对数组进行迭代。我想知道这个逻辑在映射完数组后是否会被弄糊涂。您是否有可能多次调用processData?这可能会导致1个async close db语句中断另一个processData调用。我多次调用processData()
,但在实际代码中,打开和关闭数据库的调用仅调用一次,此函数除外。我在这个函数中包含了调用,只是为了简化描述。谢谢,@Bergi。当您指出..map()
同步运行时,这是显而易见的。我想我把自己弄糊涂了,因为它被包装在一个Promise.all()
中,这让我的大脑想到“这一点以后会发生”。我将再看一看disposers,尽管上次我查看它时文档有点深奥。