【问题标题】:Program doesn't await async function before continuing flow程序在继续流程之前不等待异步功能
【发布时间】:2020-11-22 18:54:15
【问题描述】:

在下面的代码中,csv2pg 函数是异步的

const postUsages = async (req: MulterRequest, res: Response, next: any) => {
  try {
    const result = await csv2pg(req, next);

    res.status(200).json({
      msg: 'File uploaded/import successfully!',
      file: req.file,
    });
  } catch (err) {
    res.status(400).json({
      msg: 'File uploaded/import failed!',
      file: req.file,
    });
  }
};

问题是,在返回 res.status(200) 之前,await 似乎没有等待函数完成

这里是被调用的 csv2pg 函数的内容(这段代码中的异步位是 forEach 和 pool.query)

const csv2pg = (req: MulterRequest, next: any): any => {
  let provider_id = req.body!.provider_id;

  const filePath = appRoot + '/reports/' + req.file.filename;

  const stream = fs.createReadStream(filePath);
  const csvData: any[] = [];

  const csvStream = csv
    .parse()
    .on('data', (data: any) => {
      csvData.push(data);
    })
    .on('error', (err: any) => {
      throw err.message;
    })
    .on('end', () => {
      csvData.shift();
      csvData.forEach((row) => {
        pool.query(
          `INSERT INTO usage (date_and_time, consumption, reading_quality, provider_id)
            VALUES ((TO_TIMESTAMP($1, 'DD/MM/YYYY HH24:MI') AT TIME ZONE 'Australia/Melbourne')::TIMESTAMP WITH TIME ZONE, $2, $3, ${provider_id})`,
          row,
          (err: any) => {
            if (err) {
              next(new Error(err));
            }
          }
        );
      });
      fs.unlinkSync(filePath);
    });
  stream.pipe(csvStream);
};

另一个问题是,当出现问题时,顶部会显示另一条错误消息,表明标头已设置(当然,此时服务器已经返回给客户端)

理想情况下,当出现错误时,整个函数应该停止,返回错误消息,并等待新的传入请求

【问题讨论】:

  • 问题是在 forEach 循环中运行异步代码,检查这个答案stackoverflow.com/a/63618100/11531708
  • 您的 csv2pg 函数是一个耗时的函数。所以你最好使用一个承诺。猜测解决会解决你的问题。
  • @MohammedAmirAnsari 这只能部分解决问题,因为 poo.query 是另一个异步函数

标签: node.js typescript async-await


【解决方案1】:

为了能够等待csv2pg 完成所有异步操作,它必须返回一个promise。由于异步操作处于循环中,我们必须使用Promise.all。试试这个:

const csv2pg = (req: MulterRequest, next: any): any => {
  return new Promise((resolve, reject) => {
    let provider_id = req.body.provider_id;

    const filePath = appRoot + "/reports/" + req.file.filename;

    const stream = fs.createReadStream(filePath);
    const csvData: any[] = [];

    const csvStream = csv
      .parse()
      .on("data", (data: any) => {
        csvData.push(data);
      })
      .on("error", (err: any) => {
        reject(err.message);
      })
      .on("end", () => {
        csvData.shift();
        const promisesArray = csvData.map((row) => {
          return new Promise((resolve, reject) =>
            pool.query(
              `INSERT INTO usage (date_and_time, consumption, reading_quality, provider_id)
              VALUES ((TO_TIMESTAMP($1, 'DD/MM/YYYY HH24:MI') AT TIME ZONE 'Australia/Melbourne')::TIMESTAMP WITH TIME ZONE, $2, $3, ${provider_id})`,
              row,
              (err: any) => {
                if (err) {
                  reject(new Error(err));
                } else {
                  resolve();
                }
              }
            )
          );
        });

        Promise.all(promisesArray).then(() => {
          fs.unlinkSync(filePath);
          resolve();

        })
      });
    stream.pipe(csvStream);
  });
};

请注意,我还将您的 pool.query 包装在一个承诺中,因为此函数默认情况下不返回承诺。

【讨论】:

  • 代码不是从那个解决方案开始的。运行 nodemon,它说[nodemon] clean exit - waiting for changes before restart
  • 什么意思?我所做的只是改变csv2pg 的实现。这不会影响您的代码是否运行。
【解决方案2】:

原因可能是您在 for 循环中使用了此代码。使用 Promise.all 可以解决问题。我会向你推荐这篇文章:https://www.freecodecamp.org/news/promise-all-in-javascript-with-example-6c8c5aea3e32/.

它详细解释了一切。

【讨论】:

    猜你喜欢
    • 2018-04-19
    • 2017-11-14
    • 1970-01-01
    • 2021-07-12
    • 2020-01-15
    • 2020-12-24
    • 2020-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多