使用嵌套的Q promises进行顺序/相关操作

Isa*_*ell 2 javascript node.js q

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

这是交易.我有一个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
Run Code Online (Sandbox Code Playgroud)

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

我一直在使用Q库来避免真正深度嵌套的回调.我有一个runQuery实用程序方法,它返回一个promise并在数据库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"    
             })
         })
})
Run Code Online (Sandbox Code Playgroud)

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

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

Kri*_*wal 5

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

但是,如果您需要使用Q顺序编写承诺,则有许多选项.这是与您的伪代码形式匹配的.把它分解成更小的函数会很好.

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);
    }))
});
Run Code Online (Sandbox Code Playgroud)

这将产生一系列问题的承诺,用各自的答案数组注释,以及用他们的投票注释的答案.

另见https://github.com/kriskowal/q#sequences