如何将行传递给内部的多个请求
我有一个要求获得一系列问题
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
循环来处理这个如下。 否则,你可以使用像async
, bluebird
等承诺模块。
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
/let
variables的作用域是最接近的任何types的块(而var
variables的作用域是最接近的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));