为什么使用数据加载器进行批处理在测试中不起作用?

Why does batching with a dataloader not work in a test?

问题

我正在尝试测试以下查询的性能:

query {
  classes {
    teachers {
      user_id
    }
  }
}

当我启动我的服务器并运行通过 graphQL 游乐场进行查询时,数据加载器按预期工作并批处理查询:teachersForClasses 仅 运行 一次。

当我 运行 测试以对查询的性能进行基准测试时,teachersForClasses 运行 对 getClasses 返回的每个唯一 class 执行一次 getClasses

为什么行为不同?在这两种情况下,HTTP 请求都被发送到已经 运行ning 的服务器。

背景

我在使用 Apollo Server 创建 graphQL API 的项目中使用 node.js 的数据加载器库。

代码

function getClasses(args, ctx) {
  /* returns a list of Class objects */
}

const resolvers = {
  Class: {
    teachers: (parent: Class, _args, ctx: Context) => 
      ctx.loaders.class.teachers.load(parent.class_id)
  }
  Query: {
    class: (_parent, args, ctx): Promise<Class[]> => getClasses(args, ctx)
  }
}

加载器定义如下:

function teachersForClasses(classIds: readonly string[]) {
  console.log(classIds) // added for debugging
  /* returns an array of User objects for each class ID */
}

export const loader = {
  class: {
    teachers: new Dataloader<string, User[]>>(teachersForClasses)
  }
}

测试

在此 运行 之前,服务器已经 运行 连接到 http://localhost:8080。

const url = 'http://localhost:8080'
const request = supertest(url)

async function runQuery(token: string) {
  return request
    .post('/user')
    .set({
      ContentType: 'application/json',
      Authorization: token
    })
    .send({
      query: `
      {
        classes {
          teachers {
            user_id
          }
        }
      }`
    })
}

describe('benchmarks', () => {
  it('getTeachersForClasses', () => {
    /*populates the database with data*/

    ...

    for (let i=0; i < 10; i++) {
      console.time('query')
      const start = Date.now()
      await runQuery(userToken)
      const end = Date.now()
      console.timeEnd('query')
    }
  })
})

我发现了问题:'teachers' 有一个异步指令(权限检查),这意味着每次使用 .load() 调用数据加载器时,它都是不同事件循环的一部分 'tick' (explained here) & 因此调用没有按预期进行批处理。

这在 graphQL 游乐场中不是问题,因为我正在与管理员用户进行调用,所以该指令立即得到解决。