【问题标题】:Node.js and MySQL. forEach() inside Promise - last item is not being inserted in arrayNode.js 和 MySQL。 Promise 中的 forEach() - 最后一项未插入数组中
【发布时间】:2022-01-10 23:45:38
【问题描述】:

我在将查询的最后一个元素推入数组时遇到问题。

  • 程序应该循环遍历testArray并在数据库中搜索对应的MedikamentId
  • 然后创建一个包含这些 ID 的数组。

这几乎可以正常工作,当前的输出如下所示:[3,2,3,2,3,2,3,2,3,2,3,2,3]

但是最后一个元素不见了,这个数组的末尾应该还有一个2(总共必须有14个元素)。

当我运行循环内注释的console.log(medIdArray) 时,我得到了正确的数组。

当我将medIdArray 放入.then() 处理程序时,为什么我的最后一项没有被退回?

let testArray = [
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
];

let medIdArray = [];
let sqlGetMedId = "SELECT MedikamentId FROM Medikament WHERE Bezeichnung = ?";
let getMedId = new Promise((resolve, reject) => {
  testArray.forEach((i, idx, array) => {
    i.forEach((j) => {
      mySqlConnection.query(sqlGetMedId, j, (err, rows, fields) => {
        if (err) reject(err);
        medIdArray.push(rows[0].MedikamentId);
        //console.log(medIdArray);
        if (idx === array.length-1) resolve();
      })
    })
  })
})

getMedId.then(() => {
  console.log(medIdArray);
})

getMedId.catch((err) => {
  console.log(err);
})

【问题讨论】:

    标签: mysql node.js asynchronous foreach promise


    【解决方案1】:

    这行代码

    if (idx === array.length-1) resolve();
    

    第一次 迭代中为内部循环而不是第二次解决承诺。使用

    i.forEach((j, idx2) => {
       ...
       if (idx === array.length-1 && idx2 === i.length -1) resolve();
    }
    

    或类似的东西......

    编辑

    但是,您可能可以先展平输入数组,然后迭代展平的数组,而不是嵌套循环

    let testArray = [[..], [..]];
    let flattened = testArray.reduce((a, c) => {
      a.push(...c);
      return a;
    }, [])
    
    return new Promise((resolve, reject) => {
       flattened.forEach((elem, idx) => {
         con.query(..., (err, rows, fields) => {
           ...
           if (idx === flattened.length - 1) resolve();
         });
       });
    });
    

    或者你也可以使用Promise.all

    let getIds = Promise.all(flattened.map(med => new Promise((res, rej) => { 
      conn.query(..., med, (err, rows, fields) => {
        if (err) rej(err);
        res(rows[0].MedikamentId);
      });
    })));
    
    getIds.then(data => {
      //data is an array of query results 
    });
    

    【讨论】:

    • 非常感谢您提出的建议。扁平化输入数组的想法很好。为了更好地理解我正在编写的代码,我采纳了第一个建议,它对我来说效果很好。
    • 您实际上应该使用Promise.all() 解决方案。由于mySqlConnection.query() 的异步性,结果到达的顺序是任意的,最后收到的结果不一定与最后的查询相对应。因此if (idx === flattened.length - 1) resolve() 可能会提前触发,并且承诺将在所有结果到来之前得到解决。这个问题可以通过记录结果(并相应地编写测试)来解决,但是当Promise.all() 为您完成所有这些时,为什么还要麻烦呢?
    猜你喜欢
    • 1970-01-01
    • 2013-03-15
    • 1970-01-01
    • 2015-10-28
    • 2020-02-10
    • 2014-02-21
    • 1970-01-01
    • 2013-01-30
    • 1970-01-01
    相关资源
    最近更新 更多