You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在同一Express路由中对同一张表执行两个查询并在同一EJS文件中使用返回值?

在Express路由中并行执行多个SQL查询并传递数据到EJS视图

我明白你的问题啦——你现在的代码里两次调用了res.render(),这肯定会出问题,因为一个HTTP请求只能发送一次响应。而且两个异步查询的执行顺序是不确定的,很可能第二个查询还没完成,第一个就已经把响应发出去了。用Promise来处理异步操作确实是正确的思路,我来帮你重构代码:

首先,我们需要把基于回调的db.query转换成Promise形式,这样就能用更清晰的方式处理多个异步操作。然后我们可以并行执行两个查询,等所有结果都返回后,再一次性把所有数据传递给home.ejs。

方案一:使用Promise.all + 链式调用

// 先封装一个Promise版本的查询函数
const queryPromise = (sql) => {
  return new Promise((resolve, reject) => {
    db.query(sql, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
};

app.get('/', (req, res) => {
  // 定义两个查询的SQL语句(注意修正了你原SQL的语法错误)
  const countTotalSql = 'SELECT COUNT(*) AS count, FORMAT(SUM(donation_amount),2) AS total FROM donations;';
  const latestDonatorSql = 'SELECT CONCAT(first_name, ", ", last_name) AS latest_donator, donation_amount AS amount FROM donations ORDER BY donation_time DESC LIMIT 1;';

  // 并行执行两个查询
  Promise.all([queryPromise(countTotalSql), queryPromise(latestDonatorSql)])
    .then(([countResult, donatorResult]) => {
      // 提取两个查询的结果
      const { count, total } = countResult[0];
      const { latest_donator: donatorName, amount } = donatorResult[0] || {}; // 处理没有捐赠记录的情况

      // 一次性传递所有数据到视图
      res.render('home', {
        count,
        total,
        donatorName,
        amount
      });
    })
    .catch((err) => {
      console.error('查询出错:', err);
      res.status(500).send('服务器内部错误');
    });
});

方案二:使用async/await(更简洁易读)

如果你用Node.js 8+,async/await会让代码更直观:

// 同样先封装Promise版本的查询函数
const queryPromise = (sql) => {
  return new Promise((resolve, reject) => {
    db.query(sql, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
};

app.get('/', async (req, res) => {
  try {
    const countTotalSql = 'SELECT COUNT(*) AS count, FORMAT(SUM(donation_amount),2) AS total FROM donations;';
    const latestDonatorSql = 'SELECT CONCAT(first_name, ", ", last_name) AS latest_donator, donation_amount AS amount FROM donations ORDER BY donation_time DESC LIMIT 1;';

    // 并行执行两个查询(用Promise.all同时发起,比串行更快)
    const [countResult, donatorResult] = await Promise.all([
      queryPromise(countTotalSql),
      queryPromise(latestDonatorSql)
    ]);

    const { count, total } = countResult[0];
    // 处理可能没有捐赠记录的情况,避免报错
    const { latest_donator: donatorName, amount } = donatorResult[0] || { latest_donator: '暂无捐赠者', amount: 0 };

    res.render('home', { count, total, donatorName, amount });
  } catch (err) {
    console.error('查询失败:', err);
    res.status(500).send('服务器出错了');
  }
});

几个关键注意点:

  • 修正了SQL语法错误:你原来的第二个SQL里CONCAT的括号和AS的位置不对,我已经调整过来,还加了DESC确保拿到的是最新的捐赠记录。
  • 只调用一次res.render:所有数据准备好后再统一渲染视图,避免重复响应的错误。
  • 错误处理:用catch或者try/catch捕获错误,避免直接throw err导致服务器崩溃,同时给用户返回合适的错误响应。
  • 并行执行查询:用Promise.all同时发起两个查询,比串行执行效率更高,因为两个查询可以同时在数据库端处理。

内容的提问来源于stack exchange,提问作者Tarik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 18:37:33