【问题标题】:How do you prevent nested queries/catches in sequelize?如何防止 sequelize 中的嵌套查询/捕获?
【发布时间】:2016-08-29 02:21:11
【问题描述】:

我认为我正在尽可能地防止嵌套查询,但老实说我不确定。我知道这里的调用都可以在单个选择查询中执行,但我这样做是为了简化示例。

// This example is in TypeScript

// find user
User.find({where:{username:'user'}})

    // if found user
    .then(function(user) {

        return User.find({where:{username:'other_user'}})

            // if found other_user
            .then(function(other_user) {
                // do stuff
                return whatever_i_need
            }

            // if something went wrong, go straight to parent catch
            .catch(function(err) {
                // do stuff
                throw new Error()
            }
    }

    // if previous .then() returned success
    .then(function(data) {

        return User.find({where:{username:'yet_another_user'}})

            // if found yet_another_user
            .then(function(yet_another_user) {
                // do stuff
                return whatever_i_need_again
            }

            // if something went wrong, go straight to parent catch
            .catch(function(err) {
                // do stuff
                throw new Error()
            }
    }

    // if anything threw an error at any point in time
    .catch(function(err) {
        // handle the error
    }

但是,这会导致嵌套的 Promise,而这正是 Promise 所要防止的。这是为承诺推荐的“最大深度”,还是我错过了什么?有没有更好的方法来链接查询?

【问题讨论】:

  • this results in nested promises, which is exactly what promises are meant to prevent. - 在某些情况下需要嵌套承诺。不是说这是这样的情况,但不要盲目相信你读到的关于 Promises 的所有内容:p

标签: javascript typescript promise sequelize.js


【解决方案1】:

返回嵌套的promise,而不是在内部块中处理它以展平结构。

User.find({where:{username:'user'}})
.then(function(user) {
  if (user) { // if found user
    // do stuff
    return User.find({where:{username:'other_user'}});
  }
  throw new Error('user not-found');
})
.then(function(other_user) {
  if (other_user) { // if found other_user
    // do stuff
    return whatever_i_need;
  }
  throw new Error('other_user not-found');
})
.then(function(data) {
  return User.find({where:{username:'yet_another_user'}})
})
.then(function(yet_another_user) {
  if (yet_another_user) { // if found yet_another_user
    // do stuff
    return whatever_i_need_again;
  }
  throw new Error('yet_another_user not-found');
}
.then(function(data){
  // do stuff
})
.catch(function(err) { // if anything threw an error at any point in time
  // handle the error
}

请注意,已解决的承诺意味着查询已成功完成。就是这样。成功的查询并不能保证返回结果。空结果是已解决的承诺的有效结果。

还要注意,resolve 或 reject 回调的返回值将用已解决的 Promise 包装,然后传递给下一个 then 块,形成一个有意义的 Promise 链。感谢@Matt 关于这一点的后续反馈。

【讨论】:

  • 所以这个流程对每个查询使用.then() 并使用另一个.then() 来分析结果?
  • @Matt,是的,这就是流程变平的方式。
  • @Matt,我假设如果找不到感兴趣的用户,您想抛出错误以提前退出链。如果不是这种情况,请以任何适当的方式处理它。
  • 那些ifs 来自哪里?
  • @Bergi,它们旨在确认在解决承诺时已找到感兴趣的用户。虽然这取决于User.find 的行为,但我试图就此发出通知。
【解决方案2】:

两点:

  • 删除.catch(function(err) { throw new Error() }。它只会删除错误消息。
  • 你可以unnest内部then调用

应该是这样的

User.find({where:{username:'user'}})
.then(function(user) {
    return User.find({where:{username:'other_user'}})
})
.then(function(other_user) {
    // do stuff
     return whatever_i_need
})
// if previous .then() returned success
.then(function(data) {
    return User.find({where:{username:'yet_another_user'}})
})
// if found yet_another_user
.then(function(yet_another_user) {
    // do stuff
    return whatever_i_need_again
})
// if anything threw an error at any point in time
.catch(function(err) {
    // handle the error
})

【讨论】:

  • 这和上面的答案差不多吧?对每个查询使用 2 个.then() 调用。第一个.then() 进行后续查询,第二个.then() 处理结果?此外,很好地抓住了覆盖错误。我混合了一些代码,应该是if(row is valid) { return data } else { throw new Error() }
  • @Matt 啊,我明白了,是的,它们很相似。如果您不做 2 个异步操作,则不需要 2 个 thens,通常可以将一个返回承诺的调用合并到前一个同步调用中。顺便说一句,如果该逻辑在所有地方都相同,您可能希望将其抽象为一个额外的函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-18
  • 2021-07-12
  • 2021-08-12
  • 2019-01-18
  • 2019-10-14
相关资源
最近更新 更多