简体   繁体   English

带有 Node js 承诺链接的 For 循环

[英]For loop with Node js promise chaining

I am very new to Node js and asynchronous programming seems difficult for me to grasp.我对 Node js 很陌生,异步编程对我来说似乎很难掌握。 I am using promise-mysql to make the flow synchronous but I have hit a road block with for loop inside of a chain of promise我正在使用 promise-mysql 使流程同步,但我在承诺链中使用 for 循环遇到了障碍

I have a multiple choice question module.我有一个选择题模块。 One table stores all the mcq questions and the other stores all the related choices for the questions.一张表存储所有 mcq 问题,另一张表存储问题的所有相关选项。 I am using the output of the first query as an input to the second query and so I did promise chaining as below我使用第一个查询的输出作为第二个查询的输入,所以我承诺链接如下

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)
         })
      }
    })

I am trying to create a javascript object array which would look something like this我正在尝试创建一个 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}....
]

When I run the above code the object populates all the question's options correctly but the same question is repeated in all the q_text for all questions.当我运行上面的代码时,对象会正确填充所有问题的选项,但在所有问题的所有 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}]
]

I feel like it has something to do with asynchronous flow since console.log before the second query gets printed in all before printing anything after the second query.我觉得它与异步流有关,因为在第二个查询之后打印任何内容之前,第二个查询之前的 console.log 被全部打印出来。 Any insight would be appreciated任何见解将不胜感激

Edit: I added a sample output for better understanding.编辑:我添加了一个示例输出以便更好地理解。 As seen in the output, the options change and get stored in the js object in the for loop but the question is updated for all the objects to the last question in the for loop如输出所示,选项更改并存储在 for 循环中的 js 对象中,但所有对象的问题都更新为 for 循环中的最后一个问题

node js current working async and await , still now use to async and await , use this reference url: https://javascript.info/async-await node js 当前工作asyncawaitstill now use to async and await ,使用这个参考网址: https : //javascript.info/async-await

async and await is work as promise, await is use to wait to execute script example 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);
        }
      });
   }
 }

You have a scope problem here你在这里有一个范围问题

This is an example to reproduce your problem:这是重现您的问题的示例:

ques is a global variable that is updated in the for-loop so, when the async code ends the execution will read the global variable with the last ques = result[i] value. 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))
}

But, if you simply declare the ques like this:但是,如果您只是像这样声明ques

for (var i = 0; i < result.length; i++) {
  const ques = result[i]
  const sql_test_q_op...

all will work.一切都会好起来的。

It is a good practice to use const or let instead of var because the last one creates a global scoped variable that is dangerous.使用constlet而不是var是一个很好的做法,因为最后一个会创建一个危险的全局范围变量。


Regarding your comment: the output is empty because this for-loop is sync, so you reply in sync way to the response.关于您的评论:输出为空,因为此 for 循环是同步的,因此您以同步方式回复响应。

An example on how to manage this case could be like this:关于如何管理此案例的示例可能如下所示:

'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))
}

Consider that there are many possibilities to implement this:考虑到实现这一点有很多可能性:

  • use for async iterator to run query sequentially 用于异步迭代器按顺序运行查询
  • improve performance by run only one query with a in condition instead of a query for each q_id and manage the result with some code to group the results通过只运行一个带有in条件的查询而不是每个q_id的查询来提高性能,并使用一些代码管理结果以对结果进行分组
  • using the promise array as in the example在示例中使用 promise 数组

Go deeper and choose the one that fits best for your need.深入了解并选择最适合您的需求。

Important: .catch always the promise chain!重要提示: .catch总是承诺链!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM