这个 asyncHandler 函数是如何工作的?

How does this asyncHandler function work?

我说的是这个函数:

const asyncHandler = (fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);

我很想知道当我们传递这个函数时会发生什么:

getBootcamps = asyncHandler(async (req, res, next) => {
  const bootcamps = await Bootcamp.find();
  res.status(200).json({ success: true, count: bootcamps.length, data: bootcamps });
});

它根据现有函数 fn 生成一个新函数,签名为:

(req, res, next)

这个生成函数的主体是:

return Promise.resolve(fn(req, res, next)).catch(next)

它的作用是:

  • 使用参数 (req, res, next)
  • 调用 fn(底层处理程序)
  • fn 调用的 return 值传递给 Promise.resolve() - 这会将其转换为一个 Promise(如果它还不是 Promise)
  • 注册一个回调(next)当承诺被拒绝时

您发布的代码似乎是一个 Adapter,它将异步函数转换为使用基于 next(err) 的错误处理(最有可能用于 express 框架) .然而,值得注意的是,它似乎只关心错误情况——发送响应仍然是异步函数的责任,从而结束请求处理。

一些其他的 Web 框架使这个步骤变得不必要 - 例如,fastify 可以直接使用异步函数作为处理程序,并且简单地 return 响应对象而不是显式 .json() 调用(在后台执行 res.end())。

A combinator 是一个高阶函数,它仅使用函数应用程序和先前定义的组合器来定义其参数的结果。

所以我们有一个组合器,asyncHandler -

const asyncHandler = (fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next)

我们有 getBootcamps -

const getBootcamps = asyncHandler(...)

所以我们填写asyncHandler-

的定义
const getBootcamps = (fn) => (req, res, next) =>
  Promise.resolve(fn(req, res, next)).catch(next)

其中第一个参数 fn 等于 -

async (req, res, next) => {
  const bootcamps = await Bootcamp.find();
  res.status(200).json({ success: true, count: bootcamps.length, data: bootcamps });
}

这样就变成了-

const getBootcamps = (req, res, next) =>
  Promise.resolve((async (req, res, next) => {
    const bootcamps = await Bootcamp.find();
    res.status(200).json({ success: true, count: bootcamps.length, data: bootcamps });
  })(req, res, next)).catch(next)

因此,正如 asyncHandler 的名称所暗示的,它接受一个 fn,它被视为一个 异步处理程序 fn 可以 return 一个承诺,asyncHandler 将正确包装它并自动连接 next 回调以正确处理错误。相关:What do multiple arrow functions mean in JavaScript?

这是一个有效的组合器,因为它使您不必为 每个 异步处理程序编写此 try-catch 样板 -

// without asyncHandler 

async function  getBootcamps (req, res, next) {
  try {
    const bootcamps = await Bootcamp.find()
    res.status(200).json({ success: true, count: bootcamps.length, data: bootcamps })
  }
  catch (err) {
    next(err)
  }
}

相反 asyncHandler 允许您专注于“成功”路径并自动为您处理“错误”路径 -

// with asyncHandler

const getBootcamps = asyncHandler(async (req, res, next) => {
  const bootcamps = await Bootcamp.find()
  res.status(200).json({ success: true, count: bootcamps.length, data: bootcamps })
})