.then(Promise.mapSeries(...)) 的行为是否与 .then(function() { return Promise.mapSeries(...); }) 不同?

Does .then(Promise.mapSeries(...)) behave differently than .then(function() { return Promise.mapSeries(...); })?

我最初假设将裸 Promise.mapSeries(...) 调用作为参数传递给 .then() 与将其包装在函数中是一样的,例如 .then(function() { return Promise.mapSeries(...); })。写完这个问题后,我不再完全确定它为什么有效。

在下面的简化代码中,我异步打开了几个数据库 (openDBAsync()),然后读取了一个包含 JS object 的文件。我使用 _.map() 遍历 object 中的所有 key/value 对并在数据库中异步更新它们的值,同时跟踪哪些满足特定条件(值是否为奇数) ,在这个玩具示例中)。 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 中的错误,或者更可能的是,我不了解 Promise.mapSeries() 工作原理的一些基本知识。任何指导将不胜感激。

much more likely, I'm not understanding something fundamental about how Promise.mapSeries() works

不,这似乎是对.then(…)工作原理的误解。

承诺的 then 方法总是采用 回调函数 (如果你传递任何其他东西 [但 null],Bluebird 应该吐发出警告!)。通过调用 .then(Promise.mapSeries(…)),您传递的是一个承诺,它只是被 忽略 。被忽略,也没有等待任何东西,导致数据库过早关闭的错误。

But the direct call to Promise.mapSeries() doesn't get applied to the array immediately. If it was, the array would be empty and this code wouldn't work at all.

是的。您的数组由 _.map 回调填充,该回调在调用 thenmapSeries 之前同步执行。

所以解决方案确实是将调用包装在函数表达式中,只有在Promise.all(…)满足时才会执行,其结果不会然后被忽视,而是等待。可能会有更多不同的解决方案,具体取决于您希望允许的并行执行程度。

顺便说一句,鉴于您正在进行数据库事务,您当前的代码非常脆弱。查看 .