Bluebird Promise 串行迭代,并解析为修改后的数组?

Bluebird Promise serial iteration, and resolve to modified array?

我有这个承诺,如果在数据库中找不到它,我会创建一个新的 Item 文档,然后将其存储在以前创建的 Collection 文档中..

Collection 文档是数组中的第一个字符串,数组中的任何后续索引都转换为一个或多个 Item 文档。

Promise.each "Resolves to the original array unmodified"Promise.each 中的最后一个 return 正在渲染对象,但随后的 .then 生成原始数组。

这是承诺(为了便于阅读而缩写):

globalVar = true;
collectionId = "";
var itemSeries = Promise.each(items, function(element) {
    if (globalVar == true) {
        return Models.Collection.findOneAsync({
            "name": element
        })
        .then(function(collection) {
            // promise chain similar to the following else..
            // set the collectionId var to an _id
        });
    } else {
        return Models.Items.findOneAsync({
            "name": element
        })
        .then(function(item) {
            if (item == null) {
                return Models.Labels.findOneAsync({
                    "title": element
                })
                .then(function(label) {
                    var newItem = new Models.Items({
                        name: element,
                        label: label._id
                    });
                    return newItem.saveAsync();
                }).then(function() {
                    return Models.Items.findOneAsync({
                        "name": element
                    });
                }).then(function(item) {
                    item.collection = collectionId;
                    return item.saveAsync();
                }).then(function() {
                    return Models.Items.findOneAsync({
                        "name": element
                    });
                }).then(function(item) {
                    allItems.push(item);
                    console.log("allItems: [ ");
                    console.log(allItems);
                    return allItems;
                });
            }
        });
    }
}).then(function(allItems) {
    console.log("allItems: [ ");
    console.log(allItems);
    return allItems;
});

这是 Promise.each 中的最后一个 console.log

allItems: [ 
[ { _id: 54eec5f2b9fb280000286d52,
    name: 'one',
    label: 54eec5f2b9fb280000286d51,
    collection: 54eec5f2b9fb280000286d50,
    __v: 0 },
  { _id: 54eec5f2b9fb280000286d54,
    name: 'two',
    label: 54eec5f2b9fb280000286d53,
    collection: 54eec5f2b9fb280000286d50,
    __v: 0 } ]

然后在随后的 .then(function(allItems) { 这是最后一个 console.log:

allItems: [ 
[ 'collectionName', 'one', 'two' ]

此外,= Promise.each 稍后在 Promise.join?

中呈现 undefined 的变量 itemSeries

.each函数不会改变通过链的值:

我简化了你的代码,作为我假设的输入:

var items = ['one','two'];

对于您的代码:

Promise.each(items, function(element) {
    return element+'.';
    //return Promise.resolve(element+'.');
})
.then(function(allItems) {
    console.dir(allItems);
});

结果仍将是 ['one','two'],因为这是数组 items 的解析值。 each 中的返回值不影响传递给链式 then.

的值的内容

另一方面,.map函数会产生这样的效果:

Promise.map(items, function(element) {
    return element+'.';
    //return Promise.resolve(element+'.');
})
.then(function(allItems) {
    console.dir(allItems);
});

此处return value 值将用于创建一个新数组,然后将其传递给then。这里的结果是 ['one.','two.'].

你代码中出现的两个allItems是不同的对象。

编辑 对于带有映射的串行迭代,我会编写一个这样的辅助函数:

 function mapSeries(things, fn) {
     var results = [];
     return Promise.each(things, function(value, index, length) {
         var ret = fn(value, index, length);
         results.push(ret);
         return ret;
     }).thenReturn(results).all();
 }

来源:Implement Promise.series

Bluebird 现在原生实现了 mapSeries,参见 http://bluebirdjs.com/docs/api/promise.mapseries.html

看起来 Promise.each 仍然是 returns 不幸的是 v3.x.x 中的原始数组。