0

我对 data-loader 真正感兴趣的是每个请求的缓存。例如说我的 graphql 查询需要调用 getUser("id1") 3x。我想要一些东西来重复那个电话。

然而,似乎使用数据加载器我需要将一组键传递到我的批处理函数中,并且多个请求将被批处理到一个 api 调用中。

这让我做了一些我不喜欢的假设:

1.)我正在调用的每个服务都有一个批处理 api(我处理的一些服务没有)。

2.) 如果多个调用被批处理成 1 个 api 调用,并且该调用失败,因为其中 1 个项目未找到。通常我可以通过为该字段返回 null 来处理这个问题,这可能是一个有效的情况。但是,现在我的整个调用可能会失败,如果批处理 API 由于未找到 1 项而决定抛出错误。

无论如何都可以将数据加载器与单键请求一起使用。

4

2 回答 2

1

这两个假设都是错误的,因为批处理功能的实现最终取决于您。如文档中所述,编写批处理功能时的唯一要求如下:

批量加载函数接受一个键数组,并返回一个 Promise,该 Promise 解析为一个值数组或错误实例。

因此,底层数据源不需要也接受 ID 数组。并且不需要一个或多个失败的调用来导致整个函数抛出,因为您可以为返回的数组中的任何特定 ID 返回 null 或错误实例。事实上,你的批处理函数不应该抛出,而是应该总是返回一个包含一个或多个错误的数组。

换句话说,批处理函数的实现可能类似于:

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
    }
  }))
}

值得注意的是,也可以将 设置maxBatchSize1有效禁用批处理。但是,这不会改变批处理函数实现方式的要求——它总是需要一个 ID 数组,并且总是需要返回一个与 ID 数组长度相同的值/错误数组。

于 2020-04-03T22:26:35.067 回答
0

丹尼尔的解决方案非常好,实际上是我迄今为止使用的,在将其提取到辅助函数中之后。但我刚刚找到了另一个不需要那么多样板代码的解决方案。

new DataLoader<string, string>(async ([key]) => [await getEntityById(key)], {batch: false});

当我们设置时batch: false,我们应该总是得到一个大小为 1 的键数组作为参数传递。因此,我们可以简单地对其进行解构并返回一个包含数据的单一大小的数组。注意返回值周围的括号!如果您忽略这些,这可能会出现严重错误,例如对于字符串值。

于 2020-12-01T00:49:30.653 回答