Sequelize Promises - 链式 Promises 和 Bluebird 的 Promise.each、Promise.map、Promise.all 等

3
我在用户控制器中有一个索引操作,我想执行两个任务,并且不希望执行所需的 res.json() 方法,直到它们都有机会完成。
我有一个友谊加入模型,它连接了用户。一个列是frienderId,另一个列是friendedId。在下面的索引函数中,期望的结果是我最终将得到一个单一的用户对象,即一个朋友。下面有两个 promise 的原因是因为该用户既可以在frienderId列中,也可以在friendedId列中,因此我必须解析 req.user 的朋友可能出现两种情况。
问题是最终返回的事物,即 res.json(result),始终返回正确的朋友,但总是返回一个空数组[],要么在所需对象之前,要么在其后。我知道这个空数组来自其中一个两个 promise 场景,在这些场景中没有找到任何结果。是否有某种方法代替 resolve,比如说拒绝? 如果被调用,整个 promise 将不会被推到 promise 数组中吗? 然后我就可以测试 if (!friended) {reject} 或者 if (!friender) {reject}
我知道 .each 正在枚举每个 promise 并给出每个 promise 的结果。然而,我不想要每个 promise 的结果,我只想访问每个 promise 运行的副作用。
谢谢!
index: function(req, res) {
    var promiseArray = [];

    promiseArray.push(new Promise(function(resolve) {
      user.findById(req.user.id).then(function(user) {
        user.getFrienders({
          where: {
            username: req.body.username
          }
        }).then(function(friender) {
          resolve(friender[0])
        })
      })
    }));

    promiseArray.push(new Promise(function(resolve) {
      user.findById(req.user.id).then(function(user) {
        user.getFriendeds({
          where: {
            username: req.body.username
          }
        }).then(function(friended) {
          resolve(friended[0])
        })
      })
    }));

    Sequelize.Promise.map(promiseArray, function(result) {
      res.json(result);
    });
}

另一个奇怪的事情是,当我在顶部的var promiseArray下添加一个未定义的变量friend时,而不是仅在底部简单地使用res.json(result),然后在Sequelize.Promise.map函数中使用console.log(friend)时,结果是两个值。第一个是未定义的,然后是正确的朋友对象,或者反之亦然,具体取决于用户存在的列(frienderId或friendedId)。非常困惑,不知道如何在世界上记录单个变量会导致记录两个完全不同的值,一个紧接着另一个。谢谢。 - user6823414
1个回答

3
首先,你使用 Promise 有些冗余。由于 findById() 函数返回一个 promise,你只需要处理它即可。你不需要创建一个新的 Promise。你可以这样写:promiseArray.push(user.findById ...)。你几乎正确地使用了 then。传递到 then 中的函数在 promise 解决后将被调用,也就是在 findById 函数完成并返回值后调用。 then 本身返回一个 promise,该 promise 通过其回调返回的值解决。因此,在所有操作完成时,无论你想要什么值最终出现在 promiseArray 中,我假设是 friended[0]friender[0],你只需要在最后一个 then 函数中返回该值即可。在第一个 then 函数内,你还应该写上 return user.findFriends( ...
接下来你需要处理从findById函数返回的Promise被拒绝的情况。你可以用两种方法来处理。首先,你可以传递第二个回调函数给then,在Promise被拒绝时调用它,并将拒绝原因作为其参数。而不是向then中传入两个函数,你可以使用catch来替代then,这是我个人更喜欢的做法,并将拒绝回调传递给catchcatch也返回一个Promise,该Promise通过其回调返回的值解决。你可以选择返回传入的原因,或者任何你想要的值。所以,在错误被拒绝的情况下,catch返回的内容将成为你的Promise数组中的结果。

阅读Promise文档可能会对你有所帮助。坦白地说,当我刚开始学习Promise时,我也遇到了一些困难,但是在阅读文档并实践示例后,你就能掌握它的使用方法并看到Promise的实用性。

如果是我,这就是我会重构代码的方式。
    var frienderPromise = user.findById(req.user.id)
          .then(function(user) {
            return user.getFrienders({
              where: { username: req.body.username }
            });
          })
          .then(function (friender) {
            return friender[0];
          })
          .catch(function (reason) {
            return reason; // or whatever else you want to end up in the promisesArray on rejection
          });

    var friendedPromise = user.findById(req.user.id)
          .then(function(user) {
            return user.getFriendeds({
              where: { username: req.body.username }
            });
          })
          .then(function (friended) {
            return friended[0];
          })
          .catch(function (reason) {
            return reason;
          });

    promiseArray.push(frienderPromise);
    promiseArray.push(friendedPromise);

你可以保持其他部分不变。最后,你仍然可以像目前一样调用Sequalize。虽然应该是return Sequalize...。如果你不想保留坏的结果,你也可以考虑使用Promise.filter代替.map。所以你可以这样做:
    return Sequelize.Promise.filter(promiseArray, function(result) {
      if (/* make sure it's result you want */)
        res.json(result);
    });

个人而言,我会进一步将所有承诺业务移至另一个函数中,该函数与res无关,并以此结束。
    return Sequelize.Promise.filter(promiseArray, function(result) {
      return result === /* result you want */;
    });

进入您的index函数后,您可以调用以下代码:

    return friendsPromiseFunction().then(function (results) {
      res.json(results);
    })

这会使事情更清晰。


最终我没有使用Bluebird Promise方法,而是选择了常规的sequelize promise链。这个过程对我来说是一个实验,我没有意识到我可以在FRIENDED上进行查询,然后简单地使用.then调用,在FRIENDER上做同样的查询,然后就可以了。然后,我能够在承诺链下面的几个查询中轻松访问FRIENDED和FRIENDER作为返回值。感谢您的帮助!点赞。 - user6823414

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接