使用Node js的For循环承诺链接

时间:2019-03-27 08:46:07

标签: javascript node.js asynchronous promise

我对Node js非常陌生,异步编程对我来说似乎很难理解。我正在使用promise-mysql使流程同步,但是我遇到了一个Promise链中带有for循环的路障

我有一个多项选择题模块。一个表存储了所有mcq问题,另一表存储了问题的所有相关选择。我将第一个查询的输出用作第二个查询的输入,因此我保证按如下所述链接

Last login: Sun Mar 24 21:17:01 on ttys000
azfars-MacBook-Pro:~ ausieebilal$ npm run build
npm ERR! missing script: build

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/ausieebilal/.npm/_logs/2019-03-24T16_32_23_995Z-debug.log
azfars-MacBook-Pro:~ ausieebilal$ 

我正在尝试创建一个看起来像这样的javascript对象数组

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

当我运行上面的代码时,该对象正确地填充了所有问题的选项,但是所有问题的所有q_text中都重复了相同的问题。

[{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}....
]

我感觉这与异步流有关,因为在第二次查询之前先打印console.log,然后再打印第二次查询前的所有内容。任何见识将不胜感激

编辑:我添加了一个示例输出以更好地理解。从输出中可以看到,这些选项会更改并存储在for循环的js对象中,但所有对象的问题都会更新为for循环中的最后一个问题

2 个答案:

答案 0 :(得分:2)

node js当前工作的asyncawaitstill now use to async and await, 使用以下参考网址:https://javascript.info/async-await

异步和等待是应有的承诺,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);
        }
      });
   }
 }

答案 1 :(得分:1)

您在这里遇到示波器问题

这是重现您的问题的示例:

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...

一切正常。

使用constlet代替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))
}

请考虑有多种实现方法:

  • 使用for async iterator顺序运行查询
  • 通过仅运行一个具有in条件的查询而不是对每个q_id进行查询来提高性能,并使用一些代码对结果进行分组来管理结果
  • 如示例中那样使用promise数组

深入了解,然后选择最适合您的需求。

重要提示:.catch始终是应许链!