我可以在不进行批处理的情况下使用数据加载器吗
Can I use data loader without batching
我对数据加载器真正感兴趣的是每个请求的缓存。例如说我的 graphql 查询需要调用 getUser("id1") 3x。我想要一些东西来删除那个电话。
然而,对于数据加载器,我似乎需要将一组键传递到我的批处理函数中,并且多个请求将被批处理到一个 api 调用中。
这让我做出了一些我不喜欢的假设:
1.) 我调用的每个服务都有一个批处理 api(我处理的一些服务没有)。
2.) 如果多个调用被合并为 1 个 api 调用,并且该调用因未找到其中 1 个项目而失败怎么办。通常我可以通过为该字段返回 null 来处理这个问题,这可能是一个有效的案例。然而,现在我的整个调用可能会失败,如果批处理 API 决定抛出一个错误,因为找不到 1 个项目。
有单键请求的数据加载器吗?
这两种假设都是错误的,因为批处理功能的实现最终取决于您。如 documentation 中所示,编写批处理函数时的唯一要求如下:
A batch loading function accepts an Array of keys, and returns a Promise which resolves to an Array of values or Error instances.
所以底层数据源不需要也接受 ID 数组。并且不需要一个或多个失败的调用导致整个函数抛出,因为您可以 return 数组中任何特定 ID 的空值或错误实例 return。事实上,您的批处理函数应该 永远不会 抛出,而应该总是 return 一个或多个错误的数组。
换句话说,批处理函数的实现可能类似于:
async function batchFn (ids) {
const result = await Promise.all(ids.map(async (id) => {
try {
const foo = await getFooById(id)
return foo
} catch (e) {
// either return null or the error
}
}))
}
值得注意的是,也可以将 maxBatchSize
设置为 1
以有效禁用批处理。但是,这不会改变批处理函数的实现方式的要求——它总是需要一个 ID 数组,并且总是需要 return 一个 values/errors 的数组,其长度与ID 数组。
Daniel 的解决方案非常好,实际上是我目前使用的解决方案,在将其提取到辅助函数中之后。
但我刚刚找到了另一个不需要那么多样板代码的解决方案。
new DataLoader<string, string>(async ([key]) => [await getEntityById(key)], {batch: false});
当我们设置 batch: false
时,我们应该总是得到一个大小为 1 的键数组作为参数传递。因此,我们可以简单地对其进行解构,并 return 一个包含数据的单一大小的数组。注意 return 值周围的括号!如果你忽略这些,这可能会出错,例如对于字符串值。
我对数据加载器真正感兴趣的是每个请求的缓存。例如说我的 graphql 查询需要调用 getUser("id1") 3x。我想要一些东西来删除那个电话。
然而,对于数据加载器,我似乎需要将一组键传递到我的批处理函数中,并且多个请求将被批处理到一个 api 调用中。
这让我做出了一些我不喜欢的假设:
1.) 我调用的每个服务都有一个批处理 api(我处理的一些服务没有)。
2.) 如果多个调用被合并为 1 个 api 调用,并且该调用因未找到其中 1 个项目而失败怎么办。通常我可以通过为该字段返回 null 来处理这个问题,这可能是一个有效的案例。然而,现在我的整个调用可能会失败,如果批处理 API 决定抛出一个错误,因为找不到 1 个项目。
有单键请求的数据加载器吗?
这两种假设都是错误的,因为批处理功能的实现最终取决于您。如 documentation 中所示,编写批处理函数时的唯一要求如下:
A batch loading function accepts an Array of keys, and returns a Promise which resolves to an Array of values or Error instances.
所以底层数据源不需要也接受 ID 数组。并且不需要一个或多个失败的调用导致整个函数抛出,因为您可以 return 数组中任何特定 ID 的空值或错误实例 return。事实上,您的批处理函数应该 永远不会 抛出,而应该总是 return 一个或多个错误的数组。
换句话说,批处理函数的实现可能类似于:
async function batchFn (ids) {
const result = await Promise.all(ids.map(async (id) => {
try {
const foo = await getFooById(id)
return foo
} catch (e) {
// either return null or the error
}
}))
}
值得注意的是,也可以将 maxBatchSize
设置为 1
以有效禁用批处理。但是,这不会改变批处理函数的实现方式的要求——它总是需要一个 ID 数组,并且总是需要 return 一个 values/errors 的数组,其长度与ID 数组。
Daniel 的解决方案非常好,实际上是我目前使用的解决方案,在将其提取到辅助函数中之后。 但我刚刚找到了另一个不需要那么多样板代码的解决方案。
new DataLoader<string, string>(async ([key]) => [await getEntityById(key)], {batch: false});
当我们设置 batch: false
时,我们应该总是得到一个大小为 1 的键数组作为参数传递。因此,我们可以简单地对其进行解构,并 return 一个包含数据的单一大小的数组。注意 return 值周围的括号!如果你忽略这些,这可能会出错,例如对于字符串值。