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,尽管上次我查看它时文档有点深奥。