NodeJS - 内部循环承诺

时间:2018-03-20 14:21:42

标签: node.js promise

我今天的问题与循环中的promises有关。在这里,我将放置我的代码,你可以看到它做了一些事情。首先,它在我的所有事件中循环,并将它在其中找到的日期拆分为3个字段,以将其插入到SQL数据库中。

总共填写2个表,一个包含日期,另一个包含实际事件。问题是当这个代码被执行时,它一直循环到结束并一次完成日期分配,然后它开始释放promises。这使我的函数插入x次相同的日期和事件(其中x是我的events数组的长度)。

现在,为什么会这样?我完全研究并实施了这个问题的承诺,但似乎仍然存在。有人可以向我解释我做错了什么吗?另外,你认为这段代码有点像“厄运的金字塔”吗?非常感谢提前!

events.forEach(function (event) {
        // Simple date formatting
        dayFormatted = event.day.split("_");
        year = dayFormatted[0];
        month = dayFormatted[1];
        day = dayFormatted[2];

        // Check if the row already exists ...
        SQLCheckTableRow(`day`, year.toString(), month.toString(), day.toString()).then(function (skip) {
            // ... if not it skips all this part
            if (!skip) {
                // Create, if it doesn't exist already, a date table that is going to be connected to all the events and fill it
                SQLFillTable(`date, `null, "${year}" , "${month}" , "${day}", null`).then(function () {
                    let values = []
                    event.ons.forEach(function (on) {
                        on.states.forEach(function (event) {
                            values = [];
                            values.push(Object.keys(event.data).map(function (key) {
                                return event.data[key];
                            }));

                            SQLFillTable(`event`, values).then();
                        })
                    })
                })
            }
        })
    })

1 个答案:

答案 0 :(得分:4)

当你在forEach循环中进行异步调用时,它不会等到调用完成。如果你想一个接一个地发起异步电话,你应该使用'来表示'循环而不是。如果要并行运行它们,可以将promises推送到数组,然后使用Promise.all(arrayOfPromises).then((result)=> {})获取promise调用的结果。这里的结果将是异步调用的数组,其顺序与promise数组相同。

如果你想让你的代码更容易阅读,而不是有厄运的金字塔,那么习惯使用async..await。在这里,我使用for..of循环重构了你的代码。如上所述,如果要并行运行异步调用,请使用Promise.all。

async function queryTable() {
  for (let event of events) {
    // Simple date formatting
    let dayFormatted = event.day.split("_");
    let year = dayFormatted[0];
    let month = dayFormatted[1];
    let day = dayFormatted[2];

    try{
      let skip = await SQLCheckTableRow(`day`, year.toString(), month.toString(), day.toString());
      if (!skip) {
        // Create, if it doesn't exist already, a date table that is going to be connected to all the events and fill it
        await SQLFillTable('date', null, year, month , day, null);

        for (let on of event.ons) {
          const values = [];
          values.push(Object.keys(on.data).map(key => on.data[key]));

          await SQLFillTable('event', values);
        }
      }
    } catch(err) {
      console.error(err);
    }
  }
}