基于查询参数的可选承诺步骤

Optional promise-step based on query parameter

我有一个从数据库中检索博客文章的函数。相同的功能用于特定类别的博客文章。这是查询:

Post.find( params ).limit(5)

然而,当要查找一个类别时,必须首先检索类别的 id(查询参数是它的永久链接):

Category.findOne({ permalink: req.params.category})

我如何使用 promises 来避免像这样写重复的东西:

// a category is present
if (typeof req.params.category !== 'undefined'){
  Category.findOne({ permalink: req.params.category}).then(function(category){
    params.category = category.id
    Post.find(params).limit(5).exec(function(err,posts){
      // yada-yada
    })
  }
}
// no category
else {
  Post.find(params).limit(5).exec(function(err,posts){
    // yada-yada
  })
}

假设您可以访问 BuiltIn Promise Object

,我想出了这个解决方案
Promise.resolve(req.params.category)
  .then(function (categoryParam) {
    if (categoryParam) {
      // if you return a promise then the `then` function stored in the
      // previous promise will be executed when this promise (the one returned
      // here) is resolved
      return Category
        .findOne({ permalink: categoryParam})
        .then(function (category) {
          return category.id;
        });
    } else {
       // nothing to do here so the resolution value of this promise is undefined
    }
  })
  .then(function (categoryId) {
      if (categoryId) {
        // checks the existance of the categoryId
        params.category = categoryId;
      }

      Post
        .find(params)
        .limit(5)
        .exec(function(err,posts){
          // yada-yada
        })
  })

让我解释一下上面的解决方案:

  1. 让我们从一个承诺开始,它的解析值为请求的 category 参数
  2. 如果参数存在,则意味着我们必须在发出 Post 请求之前根据参数进行查询以查找类别,在我见过的大多数承诺实现中,如果您 return 来自 .then 的承诺,然后存储在前一个承诺中的 .then 回调将在满足 returning 值时执行,(我没有使用内置 Promise 对象进行测试但是例如来自 KrisKowal 的 q 能够解析任何类似 promise 的对象)这里就是这种情况,因为我不知道 Category.findOne({ permalink: categoryParam}) returns 的 promise 结构,在任何情况下当获取类别的查询完成时,returning 承诺的实现值将是类别的 id
  3. 在最后的 then 中,我们必须检查 categoryId 参数是否存在(它可能已从之前的 then 中 return 编辑),如果存在则用它更新 params 对象

您可以为 params 做出承诺 - 来自该类别 ID 请求,或者在不需要时简单地使用 Promise.resolve。然后,您可以简单地链接您的 find 调用:

((typeof req.params.category !== 'undefined')
  ? Category.findOne({permalink: req.params.category}).then(function(category){
        params.category = category.id
        return params;
    })
  : Promise.resolve(params)
).then(function(p) {
    return Post.find(p).limit(5).exec();
}).then(function(posts) {
    // yada-yada
});