如何将行传递给内部的多个请求

我有一个要求获得一系列问题

con.query('select * from questions where `quizId` = ? ', quizId, function(err, rows) 

那么我需要得到每个问题的答案。

 for(var i=0; i < rows.length; i++){ answer.getAllByQuestionId(rows[i].id, function(err, data){ 

我得到答案和问题没有任何麻烦。 但是由于rows[i] is undefined我无法将答案添加到每个问题中

这是整个方法:

 this.getAllByQuizId = function(quizId, callback) { connection.acquire(function(err, con) { con.query('select * from questions where `quizId` = ? ', quizId, function(err, rows) { if (err) callback(err); completed_requests = 0; for(var i=0; i < rows.length; i++){ answer.getAllByQuestionId(rows[i].id, function(err, data, rows){ rows[i].answers = data; completed_requests++; if (completed_requests == rows.length - 1) { callback(null, rows); } }); } }); }); } 

原因是, for循环中的i值在每次迭代中发生变化,而函数answer.getAllByQuestionId是asynchronous的,当每次迭代调用callback函数时, i值基本上都不同于边界。 此外,函数answer.getAllByQuestionId的callback应该只有两个参数,而不是三个。

最简单的解决方法是,你可以使用rows.forEach而不是for循环来处理这个如下。 否则,你可以使用像asyncbluebird等承诺模块。

 this.getAllByQuizId = function(quizId, callback) { connection.acquire(function(err, con) { con.query('select * from questions where `quizId` = ? ', quizId, function(err, rows) { if (err) callback(err); completed_requests = 0; rows.forEach(function(row){ answer.getAllByQuestionId(row.id, function(err, data){ row.answers = data; completed_requests++; if (completed_requests == rows.length - 1) { callback(null, rows); } }); }); }); }); } 

这里有几个问题:

  • 如果你的query()callback中设置了err ,你不会提前返回。 这将导致其余的callback继续执行错误,所以if (err) callback(err)更改为if (err) return callback(err)

  • 在你的getAllByQuestionId()callback中, rows[i]不会是你期望的,因为在callback执行的时候i的值已经等于rows.length而不是在调用getAllByQuestionId()的时候行的索引。 有几个解决scheme,包括:

    • 使用const / let存储当前行,因为const / letvariables的作用域是最接近的任何types的块(而varvariables的作用域是最接近的function块):

       for (var i = 0; i < rows.length; ++i) { const row = rows[i]; answer.getAllByQuestionId(row.id, function(err, data, rows) { row.answers = data; if (++completed_requests === rows.length) callback(null, rows); }); } 
    • 使用rows.forEach()创build一个新的函数作用域,其中当前值被正确绑定:

       rows.forEach(function(row) { answer.getAllByQuestionId(row.id, function(err, data, rows) { // ... }); }); 
  • 另一个问题是,你有两个相同的名字( rows )的variables,并不清楚你打算传递给callback() 。 我的猜测是,它是query()rows ,因为你正在设置一个.answers属性的元素。 无论哪种方式,你会想改变一个或两个的名字,以免造成问题。

  • 最后,你不处理可能传递给你的getAllByQuestionId()callback的错误。

两件事情。

如果你有一个自定义的SQL查询,并且想要得到答案,就应该使用一个连接。

 select * from questions q inner join answers a on q.questionId = a.questionId where `quizId` = ? 

但是,要使用更多近期的JavaScript语法干净地使用多个查询进行编码,您可以使用如下所示的内容:

 import promiseAllEnd from 'promiseallend'; dropErrors = async (promises) => promiseAllEnd(promises).filter(x => x!=undefined); getQuestions = async id => await conPoolQuery('select .. from questions' // getAnswers = async id => await conPoolQuery('select .. from answers'// getQuiz = async(id) => await dropErrors(await getQuestions(id).map(getAnswers));