【问题标题】:NodeJS - Promise inside loopNodeJS - 循环内的承诺
【发布时间】:2018-03-20 14:21:42
【问题描述】:

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

我总共填写了两张表,一张是日期,一张是实际事件。问题是,当这段代码被执行时,它会一直循环到最后,一次完成所有日期分配,然后开始释放承诺。这使得我的函数插入 x 次相同的日期和事件(其中 x 是我的事件数组的长度)。

现在,为什么会发生这种情况?我为这个问题研究并实现了承诺,但它似乎仍然存在。有人可以向我解释我做错了什么吗?另外,你觉得这段代码有点像“末日金字塔”吗?提前非常感谢!

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

【问题讨论】:

  • 只是调用.then() 不会让任何等待。请记住,promise 仍然是异步的,您不能进行阻塞。
  • @Bergi 那么如何阻塞循环的执行并等待函数返回呢?
  • 只有async/await (without forEach) 可以阻止循环的执行。否则使用Promise.all 等待多个承诺。
  • @Bergi Hum...我明白了,我将尝试更深入地研究 async/await。我认为它们可以替代承诺
  • 不,awaitthen 调用的语法糖。它仍然建立在承诺之上。

标签: node.js promise


【解决方案1】:

当您在 forEach 循环中进行异步调用时,它不会等到调用完成。如果您想一个接一个地触发异步调用,则应使用“for of”循环。如果你想并行运行它们,你可以将 Promise 推送到一个数组中,然后你可以使用 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);
    }
  }
}

【讨论】:

  • 很棒的工作,值得检查和 +1 只是为了努力!确实感谢简洁明了的答案。我对 NodeJS 中的 asyncronous 还是有点陌生​​,我还在学习如何正确实现它。干杯!
  • 很高兴我能提供帮助。如果你能习惯 Promise 和 async..await,它们对于编写简洁的代码真的很有帮助。不过,请注意在哪里捕获 Promise 中的错误。像往常一样没有正确或错误的答案,但尝试将api(或任何异步)调用与业务逻辑分开,并使用promise进行api/async调用并将promise本身(不附加.then)返回到业务函数,并处理在 .then().catch() 中,或者尝试 { await promiseCall } catch(err) {}
  • `如果你想一个接一个地触发异步调用,你应该使用'for of'循环来代替``文档中的这个在哪里?我在这个用例上浪费了 2 天时间!谢谢@AhmetCetin
猜你喜欢
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 2016-03-17
  • 2018-12-02
  • 2017-10-30
  • 2022-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多