【问题标题】:Call async function without blocking thread with await [duplicate]调用异步函数而不阻塞线程等待[重复]
【发布时间】:2025-12-16 03:00:01
【问题描述】:

在快速路由中,我想记录用户对数据库的访问,但不包含:

  • 在执行用户想要的任务之前等待它完成
  • 关心记录是否成功

我想知道代码是否正确。

此线程 (Down-side on calling async function without await) 基本上发布了相同的问题,但响应是避免使函数异步。然而,由于sequelizeupsert 返回了一个承诺,我不确定我是否在下面的代码中正确地做到了这一点。有人可以验证吗?

我还注意到,如果您不在异步函数的 try-catch 块中等待一个 Promise,则任何在 Promise 中抛出的错误都将无法处理。因此,我确保logAccess 捕获并处理任何错误。这是正确的做事方式吗?

const { Router } = require('express');
const moment = require('moment-timezone');
const Sequelize = require('sequelize');

function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const userTable = sequelize.define('user', {
  user_id: {
    type: Sequelize.UUID,
    primaryKey: true,
  },
  last_login: {
    type: 'TIMESTAMP',
  },
});

const logAccess = (user) => userTable.upsert({
  user_id: user.user_id,
  last_login: moment().tz('Australia/Sydney').format('YYYY-MM-DD HH:mm:ss'),
}).catch(() => console.log('Logging access to db failed'));

const makeCandy = async (user) => {
  await timeout(1000);
  return 'chocolate';
}

router.get('/get_candy', async (req, res) => {
  try {
    const user = req.body.user;
    // Log access without blocking thread
    logAccess(user);
    const candy = await makeCandy(user)
    res.status(200).send({ candy })

  } catch (e) {
    console.log(e);
  }
})

【问题讨论】:

  • 是的,就是这样。不过,我将 resolve('chocolate'); 视为错字。
  • 我投票结束这个问题,因为它最适合codereview.stackexchange.com
  • await 不会阻塞线程。它的工作方式类似于yield,因为它暂停函数并稍后恢复执行。
  • 另外,await 是 Promise 的语法糖——你只能等待那些,所以你可以重写任何 await 代码来处理 Promise。 await 有时在代码布局方面是更好的选择,它的功能并没有根本不同。
  • 您发现的另一个问题不符合您的要求,因为您需要错误处理。拥有一个不返回承诺的异步函数从来都不是一个好主意——正如他们所写的那样,它是weirdFunction。是的,像你一样使用.catch() 是可以的,尽管我宁愿把它放在调用logAccess(user) 的路由处理程序中——只是为了明确表示不等待它。

标签: javascript node.js asynchronous async-await


【解决方案1】:

不等待就抓不到:

const foo = () => Promise.reject('foo');

const bar = async() => {
  try {
    foo();
  } catch (e) {
    console.log('error caught');
  }
}

bar();

我至少得到“Uncaught (in promise)”。

我会捕捉承诺风格的错误

    logAccess(user).catch(someErrorHandlingFunction);

或在我不等待的单独函数中:

const logAccessAndCatchErrors = async (user) => {
    try {
        await logAccess(user);
    } catch(e) {
// put something here
    }
}

//...
logAccessAndCatchErrors(user);  // not `await logAccessAndCatchErrors(user)`


【讨论】: