bluebird承诺每个都不会返回最后的结果

时间:2016-04-24 15:56:36

标签: promise bluebird bookshelf.js

我使用promise.each使用bookshelfjs循环2 db查询,但是角色没有给我结果 - > roles[resource.get('name')] = role.get('name');,但是它给了我slect语句中的对象:

var promise = new Promise(
        function resolver(resolve, reject) {   
            var roles = {};
            Promise.each(user.relations.relates.models, function(relation){
                return Resource.forge({resourceId: relation.get('resourceId')}).fetch().then(function(resource){
                    return Role.forge({roleId: relation.get('roleId')}).fetch().then(function(role){
                        roles[resource.get('name')] = role.get('name');
                        return roles;
                    }).catch(function(err){
                        reject({"status":"error", "data": err});
                    });
                }).catch(function(err){
                    reject({"status":"error", "data": err});
                });
            }).then(function(roles){
              resolve(roles);
            });
        }
    );

    return promise;

2 个答案:

答案 0 :(得分:2)

来自Promise.each()的Bluebird文档:

  

解析为未修改的原始数组,此方法的意思是   用于副作用。

所以,这意味着当你这样做时:

Promise.each(array).then(function(val) {
   // iteration finished here
   // val is the original array
});

val将是您传入的原始数组,而不是您的roles对象。

由于您的roles对象位于更高的范围内,因此您可以删除roles处理程序中声明为.then()的参数,并直接引用更高范围的roles变量

你也应该避免在这里promise constructor anti-pattern而不是创建一个新的承诺,而只是返回你已经拥有的承诺。

你可以这样做:

var roles = {};
return Promise.each(user.relations.relates.models, function (relation) {
    return Resource.forge({resourceId: relation.get('resourceId')}).fetch().then(function (resource) {
        return Role.forge({roleId: relation.get('roleId')}).fetch().then(function (role) {
            roles[resource.get('name')] = role.get('name');
        });
    }).catch(function (err) {
        // repackage how the error is presented into our own object
        throw ({"status": "error", "data": err});
    });
}).then(function () {
    // make the resolved value of the final promise be the roles object
    return roles;
});

此返回承诺的已解决值将是您的roles对象。

更改摘要:

  1. Promise.each()返回承诺而不是创建新承诺(不需要在此创建新承诺)。
  2. 让拒绝传播回来,不需要手动拒绝更高级别的承诺。
  3. .then()的{​​{1}}处理程序中,删除名为Promise.each()的声明参数,因为它与更高范围的roles对象冲突。
  4. roles处理程序中返回roles,以便它成为您要返回的承诺的解析值。
  5. 删除内部.then(),因为外部.catch()也可以执行此操作。
  6. 更改.catch()以抛出重新包装的错误值。
  7. 删除内部.catch(),因为不需要它。 return roles;对象在更高的范围内始终可用,因此无需将其作为这些内部承诺的已解决值(事实上,这可能会造成混淆)。
  8. 可能的性能优化。由于您的结果都不依赖于之前的结果,因此可能您可以并行运行所有异步操作而不是串行运行,在这种情况下,您可以将roles替换为Promise.each()

答案 1 :(得分:1)

是的,对不起,我们改变主意了。

在3.x中,我们应该让.each返回结果而不是原始值,但这会破坏很多人的代码,所以我们将其更改回来并添加了mapSeries。< / p>

基本上,只要您使用.mapSeries并关注结果,就会使用each,它完全符合您的预期。如果您可以同时运行这些项目,请使用.map,因为它可能会表现得更好。