使用Async/Await与node-postgres

14

我正在使用 node-postgres 查询数据库,想知道如何使用 async/await 并正确处理错误。

这是我的一个使用示例,其中包含一个非常简单的查询:

const { Pool } = require('pg');

let config;
if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging') {
  config = { connectionString: process.env.DATABASE_URL, ssl: true };
} else {
  config = {
    host: 'localhost',
    user: 'myuser',
    database: 'mydatabase',
  };
}

const pool = new Pool(config);

async function getAllUsers() {
  let response;
  try {
    response = await pool.query('select * FROM users');
  } catch (error) {
    throw error;
  }
  return response.rows;
}

然后在我的routes.js文件中,我有以下内容:

app.get('/all_users', async (req, res) => {
  const users = await queries.getAllUsers();
  console.log(users); // returns all users fine
});

这是我目前的理解,但我认为我处理不正确,因为当出现错误时,我的应用程序将会冻结并抛出UnhandledPromiseRejectionWarning。例如,如果我提供了错误的表格。

async function getAllUsers() {
  let response;
  try {
    response = await pool.query('select * FROM notable');
  } catch (error) {
    throw error;
  }
  return response.rows;
}

UnhandledPromiseRejectionWarning: error: relation "notable" does not exist

这款应用程序将在30秒后崩溃,而我没有优雅地处理这个错误。我错过了什么?


处理错误时,您可能希望查看 await-to-js,它提供了更清晰的语法,用于处理与承诺相关的错误。 - CyberProdigy
1个回答

21

当异步函数或Promise抛出未捕获的错误时,或者捕捉器(catcher)也抛出错误时,例如您的...

throw error;

这意味着函数的调用者将面临一个被拒绝的Promise来处理。如果你在调用者中使用await,那么你还必须在调用者中使用try/catch来正确捕获错误:

app.get('/all_users', async (req, res) => {
  try {
    const users = await queries.getAllUsers();
    console.log(users);
  } catch(e) {
    // handle errors
  }
});

另一种解决该错误的方法是在使用者中不使用try/catch,而是不要在catchthrow错误:

async function getAllUsers() {
  let response;
  try {
    response = await pool.query('select * FROM users');
    return response.rows;
  } catch (error) {
    // handle error
    // do not throw anything
  }
}

但是这将使消费者更难以知道何时出现错误。

在这种情况下,async/await/try/catch 构造添加了很多语法噪声,但我认为并没有太多好处 - 目前,您可能需要考虑改用简单的 Promise:

const getAllUsers = () => pool.query('select * FROM users')
  .then(response => response.rows);

// and:
app.get('/all_users', (req, res) => {
  queries.getAllUsers()
    .then((users) => {
      console.log(users);
    })
    .catch((err) => {
      // handle errors
    });
});

asyncawait 在你需要让几个 .then 更加扁平化的时候表现出色。如果只有一个 .then,在我看来,将其转换为 async/await 语法没有太多好处。当然,这取决于你。


1
除了上述内容之外,常见的选项是使用服务器包或中间件,自动捕获未处理的错误并将其转换为HTTP 500。 - Matthew Herbst
谢谢你的回答,也许我在不必要地使用async/await,你提出了一个很好的观点。另外,感谢你澄清了我应该从调用方处理错误(这是我忽略的一个简单的事情)。 - Richlewis
通常会有一个单一的查询执行器函数,其中包含try catch,并在其他地方调用它,这样您就不必在每个地方都重复它。请参见https://node-postgres.com/guides/project-structure - Ben Creasy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接