[英]For loop with Node js promise chaining
我对 Node js 很陌生,异步编程对我来说似乎很难掌握。 我正在使用 promise-mysql 使流程同步,但我在承诺链中使用 for 循环遇到了障碍
我有一个选择题模块。 一张表存储所有 mcq 问题,另一张表存储问题的所有相关选项。 我使用第一个查询的输出作为第二个查询的输入,所以我承诺链接如下
var mcqAll=[]
var sql_test_q_ans='select qId, q_text from questions'
con.query(sql_test_q_ans)
.then((result)=>{
for(var i=0; i<result.length; i++)
{
ques=result[i]
var sql_test_q_ops='SELECT op_text, op_id FROM mc_ops WHERE
q_id='+result[i].q_id
con.query(sql_test_q_ops)
.then((resultOps)=>{
mcqAll.push({i: ques, ops: resultOps})
console.log(mcqAll)
})
}
})
我正在尝试创建一个 javascript 对象数组,它看起来像这样
[{q_text:'How many states in USA', q_ops:{1:25, 2:35, 3:45, 4:50}}
{question2 and its options}
{question3 and its options}....
]
当我运行上面的代码时,对象会正确填充所有问题的选项,但在所有问题的所有 q_text 中重复相同的问题。
[ { q_text: 'No of states in USA',
[ {op_text: '25', mc_op_id: 113 },
{ op_text: '35', mc_op_id: 114 },
{ op_text: '45', mc_op_id: 115 },
{ op_text: '50', mc_op_id: 116}],
{ q_text: 'No of states in USA',
[ {op_text: 'A', mc_op_id: 1 },
{ op_text: 'B', mc_op_id: 2 },
{ op_text: 'C', mc_op_id: 3 },
{ op_text: 'D', mc_op_id: 4}],
{ q_text: 'No of states in USA',
[ {op_text: 'Yes', mc_op_id: 31 },
{ op_text: 'No', mc_op_id: 32 },
{ op_text: 'No sure', mc_op_id: 33 },
{ op_text: 'Might be', mc_op_id: 34}]
]
我觉得它与异步流有关,因为在第二个查询之后打印任何内容之前,第二个查询之前的 console.log 被全部打印出来。 任何见解将不胜感激
编辑:我添加了一个示例输出以便更好地理解。 如输出所示,选项更改并存储在 for 循环中的 js 对象中,但所有对象的问题都更新为 for 循环中的最后一个问题
node js 当前工作async
和await
, still now use to async and await
,使用这个参考网址: https : //javascript.info/async-await
async 和 await 是作为 promise 工作的, await is use to wait to execute script
示例
let mcqAll=[]
let sql_test_q_ans='select qId, q_text from questions'
async function showAvatar() {
let result = await con.query(sql_test_q_ans);
if(result.length > 0){
array.forEach((async function (item, index, result) {
let q = result[index];
let sql_test_q_ops='SELECT op_text, op_id FROM mc_ops WHERE
q_id='+result[index].q_id
let executeQuery = await con.query(sql_test_q_ops);
if(executeQuery.affectedRows > 0){
mcqAll.push({index: q, ops: executeQuery})
console.log(mcqAll);
}
});
}
}
你在这里有一个范围问题
这是重现您的问题的示例:
ques
是一个在 for 循环中更新的全局变量,因此,当异步代码结束时,执行将读取具有最后一个ques = result[i]
值的全局变量。
'use strict'
const result = ['a', 'b', 'c']
const mcqAll = []
var ques
for (var i = 0; i < result.length; i++) {
ques = result[i]
var sql_test_q_ops = 'SELECT op_text, op_id FROM mc_ops WHERE q_id = ' + result[i].q_id
query(sql_test_q_ops)
.then(() => {
mcqAll.push({ i: ques })
console.log(mcqAll)
})
}
function query() {
return new Promise(resolve => setTimeout(resolve, 100))
}
但是,如果您只是像这样声明ques
:
for (var i = 0; i < result.length; i++) {
const ques = result[i]
const sql_test_q_op...
一切都会好起来的。
使用const
或let
而不是var
是一个很好的做法,因为最后一个会创建一个危险的全局范围变量。
关于您的评论:输出为空,因为此 for 循环是同步的,因此您以同步方式回复响应。
关于如何管理此案例的示例可能如下所示:
'use strict'
const result = ['a', 'b', 'c']
const mcqAll = []
const promiseArray = result.map(ques => {
const sql_test_q_ops = 'SELECT op_text, op_id FROM mc_ops WHERE q_id = ' + ques.q_id
return query(sql_test_q_ops)
.then(() => { mcqAll.push({ i: ques }) })
})
// Wait for all the query to complete before rendering the results
Promise.all(promiseArray)
.then(() => {
console.log({ mcqAll });
res.render('mcqAllPage', { mcqAll })
})
.catch(err => res.send(500)) // this is an example
function query() {
return new Promise(resolve => setTimeout(resolve, 100))
}
考虑到实现这一点有很多可能性:
in
条件的查询而不是每个q_id
的查询来提高性能,并使用一些代码管理结果以对结果进行分组深入了解并选择最适合您的需求。
重要提示: .catch
总是承诺链!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.