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

时间:2015-12-04 17:37:28

标签: javascript promise bluebird

我最初假设将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()如何工作的基本原理。任何指导都将非常感谢。

1 个答案:

答案 0 :(得分:3)

  

更有可能的是,我不了解Promise.mapSeries()如何工作的基本原则

不,这似乎更像是对.then(…)如何运作的误解。

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

  

但直接调用Promise.mapSeries() 并不会立即应用于数组。如果是,则数组将为空,此代码根本不起作用。

是的。在调用_.mapthen之前,mapSeries回调会同步执行您的数组。

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

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