【问题标题】:Why is this async function returning empty on the first try, but then it returns everything?为什么这个异步函数在第一次尝试时返回空,但随后返回所有内容?
【发布时间】:2021-12-11 04:02:05
【问题描述】:

我正在尝试将数据插入到我的数据库中,并且查询位于映射循环内,因此我使用异步函数等待循环结束,并将所有结果存储在我的变量“practicasAgregadas”中.

这就是我调用函数的方式:

insertarPracticas(turno_id, req.body.lista_codigos_practicas, queryInsertarPracticas)
  .then(result => {
    res.status(200).json({
      "Practicas Agregadas": result
    })
  })

这是函数:

async function insertarPracticas(turno_id, req, queryInsertarPracticas) {
  const res = await Promise.all(req.map(r => {
    connection.query(
      queryInsertarPracticas, [turno_id, r], (error2, row2) => {
        if (error2) {
          console.log("Error al insertar turno detalle (prácticas): " + r + " " + error2);
          practicasNoAgregadas += r + "-";
        } else {
          console.log("Turnos detalle agregados " + r);
          practicasAgregadas += r + "-";
          console.log("practicas " + practicasAgregadas);
        }
      });
    return practicasAgregadas;
  })
  )

  console.log("en async " + res[0]);
  return res;
}

在第一次尝试时,它返回空:

这是控制台:

在第二次尝试时,它确实返回了,但它重复了 3 次:

还有控制台:

【问题讨论】:

  • 您正在尝试将普通异步回调与 Promise 混合使用。你不能这样做,因为Promise.all() 要求你传递它在异步操作完成时解析的承诺,但你的async 函数不会这样做,因为connection.query() 不会返回承诺。
  • (error2, row2) => 这是一个回调,你需要承诺它。你可能会发现connection.query 如果没有提供回调,就会返回一个承诺,很多库似乎都在这样做现在。所以 -> const [turno_id, r] = await connection.query(),你也可以使用 try / catch 作为你的错误逻辑。请注意,您将需要 -> req.map(async r..... 来等待。
  • @jfriend00 正确的方法是什么?我怎样才能让它返回一个承诺?
  • 最简单的方法是使用数据库的 promise 接口而不是回调接口。然后connection.query() 将返回一个承诺。你不说你用的是什么数据库,但是如果是mysql,那么NPM上有一个支持promises的mysql模块。

标签: javascript express asynchronous promise


【解决方案1】:

大多数使用异步函数的现代 JS 库都会返回一个 Promise,但如果提供了回调,通常不会返回一个 Promise。

所以假设 connection.query 确实返回了一个承诺,那么下面的代码应该做你之后的事情..

async function insertarPracticas(turno_id, req, queryInsertarPracticas) {
    const res = await Promise.all(
        req.map(async (r) => {
            try {
                const row2 = await connection.query(queryInsertarPracticas, [
                    turno_id, r
                ]);
                console.log("Turnos detalle agregados " + r);
                practicasAgregadas += r + "-";
                console.log("practicas " + practicasAgregadas);
            } catch (e) {
                console.log(
                    "Error al insertar turno detalle (prácticas): " +
                        r + " " + error2
                );
                practicasNoAgregadas += r + "-";
            }
            return practicasAgregadas;
        })
    );

    console.log("en async " + res[0]);
    return res;
}

请记住,不要使用回调,否则可能会向库表明您不希望返回的承诺。

如果由于某种原因库很长时间没有更新,您将需要承诺查询..

在 node 中,有一个很好的实用程序叫做 promisify https://nodejs.org/api/util.html#utilpromisifyoriginal,它会让这更容易。

例如。

const conQuery = util.promisify(connection.query);
const row2 = await conQuery(queryInsertarPracticas....

如果回调不是 (error, result) 的形式,您将需要使用 Promise 构造函数。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise,但查看您的代码 (error2, row2) =>,这不应该是必需的。

【讨论】:

  • 直接获取支持promises的实际mysql模块不是更好吗,这样你就不必到处手动promisification了?
  • 另外,变量practicasAgregadas 是从哪里来的?因为您以不确定的顺序添加它,因为所有这些查询将并行运行并以随机顺序完成。
  • 对不起,我不能早点回复,这有效!谢谢,我将不得不了解更多有关承诺和回调的信息
  • @jfriend00 是的,如果有一个库已经使用了 Promise,那当然也是一个选择。话虽如此,这不是我经常做的事情,我记得几年前使用request,然后有一个承诺版本request-promise,它添加了相当大的依赖关系,当一个1 liner promisify 可以工作时。而且,是的,如果顺序很重要,那么您需要注意 Promise.all,但 OP 目前正在执行 += r + "-";,顺序当然在这里并不重要。
  • @Keith 我明白了!!!非常感谢,我所要做的就是 const query = util.promisify(connection.query).bind(connection);并实现您的代码。谢谢!!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-30
  • 2018-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 2021-10-31
相关资源
最近更新 更多