2

为模糊的标题道歉 - 我想不出一种简洁地总结这个问题的方法。

这是交易。我有一个 Node 控制器,它必须执行一些顺序数据库操作,如下所示:

0. Given a surveyId
1. Find all entries in the question table, where question.surveyId = surveyId.
2. For each row in the question table returned by the previous query:
    a) Find all entries in the `answer` table, where answer.questionId = question.id
    b) For each row in the answer table returned by the previous query:
       (i) Find the count of all entries in the vote table where vote.answerId = answer.id

控制器需要返回一个对象,其中包含每个 answerId 在投票表中存在条目的次数的计数。它看起来像{1:9, 2:21, 3:0},其中 1、2、3 是答案 ID,9、21 和 0 是投票表中具有该答案 ID 的行数。

我一直在使用 Q 库来避免真正深度嵌套的回调。我有一个 runQuery 实用程序方法,它返回一个承诺并在数据库 IO 完成时解决它。

现在,我有一些看起来像:

runQuery("find questions with surveyid matching given surveyid")
.then({
    "for each question row returned by query:"
         runQuery("find answers with questionid matching this question row")
         .then({
             "for each answer row returned by query:"
             runQuery("find votes with answerID matching this answer row")
             .then({
                 "for each vote row"
                      "increment the count for this answerid in the return object"    
             })
         })
})

问题是,当控制器返回时,返回对象总是空的,因为没有足够的时间来完成所有数据库操作并解决承诺(至少,我认为这是问题所在 - 显然很难解决这些异步承诺之类的问题。)

有没有更好的方法来做到这一点?我应该放弃 Q 并处理一堆嵌套回调吗?

4

2 回答 2

5

使用单个查询执行此操作是有好处的。客户端和服务器之间不会有“聊天”,在这种情况下,这将为您节省大约 2 次网络往返(通常每次十分之一秒,大约是眨眼所需的时间,也就是说,可感知的人类时间和漫长的无聊等待机器)。

但是,如果您需要使用 Q 顺序编写 Promise,有很多选择。这是与您的伪代码形式相匹配的一种。把它分解成更小的函数会很好。

runQuery("find questions with surveyId matching given surveyId")
.then(function (questions) {
    return Q.all(questions.map(function (question) {
        return runQuery("find answers matching question.id")
        .then(function (answers) {
            question.answers = answers;
            return Q.all(answers.map(function (answer) {
                return runQuery("find votes for each matching question")
                .then(function (votes) {
                    answer.votes = votes;
                    return answer;
                })
            }))
        })
        .thenResolve(question);
    }))
});

这将产生一系列问题的承诺,用相应的答案数组进行注释,并用他们的投票来注释答案。

另请参阅https://github.com/kriskowal/q#sequences

于 2013-10-18T00:48:20.217 回答
3

您不能将常规顺序编程与异步操作一起使用。因此,您不能拥有下一行顺序代码可以使用的返回对象。

相反,必须从成功处理程序调用使用返回对象的代码或承诺完成最后一个操作。这就是异步编码的工作方式,必须采用其中一种技术才能使事情正常工作。

因此,在您的伪代码中,它看起来像这样(以 ** 开头的行是我添加的):

runQuery("find questions with surveyid matching given surveyid")
.then({
    "for each question row returned by query:"
         runQuery("find answers with questionid matching this question row")
         .then({
             "for each answer row returned by query:"
             runQuery("find votes with answerID matching this answer row")
             .then({
                 "for each vote row"
                      "increment the count for this answerid in the return object"    
                  ** call function and pass it the return object 
                     to process the final result
             })
         })
})
// you cannot put code here that uses the return object because
// the return object is not yet available
于 2013-10-17T21:18:04.303 回答