这个 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 })
})
我说的是这个函数:
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
调用的 return 值传递给 Promise.resolve() - 这会将其转换为一个 Promise(如果它还不是 Promise) - 注册一个回调(
next
)当承诺被拒绝时
fn
(底层处理程序)
您发布的代码似乎是一个 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 })
})