2020 年 12 月 8 日 由 Rob Richard, Liliana Matos
Rob Richard 和 Liliana Matos 是 1stDibs.com 的前端工程师。他们一直与 GraphQL 工作组合作,作为
@defer
和@stream
指令的倡导者。
@defer
和 @stream
指令一直是备受期待的功能,自从 Lee Byron 在 2016 年 GraphQL 欧洲大会 上首次谈论它以来。在 2020 年的大部分时间里,我们一直在与 GraphQL 工作组合作,以标准化此功能。它现在是一个第二阶段提案,但为了进一步推进,我们希望 GraphQL 社区尝试使用这些指令并提供反馈。我们已经发布了 GraphQL.js
和 express-graphql
的实验版本。它们发布到 npm 中,名为 graphql@experimental-stream-defer
和 express-graphql@experimental-stream-defer
。我们鼓励所有对该功能感兴趣的人尝试这些版本,并在 为反馈创建的问题 中告诉我们结果。继续阅读以了解有关此提案的更多信息。
GraphQL 的请求/响应模型的缺点之一是,GraphQL 响应只有在整个请求处理完成后才会返回给客户端。但是,并非所有请求的数据都具有同等重要性,在某些用例中,应用程序可能能够对请求数据的一部分进行操作。如果 GraphQL 服务器能够在数据准备就绪后立即发送最重要的数据,应用程序可以加快其交互时间。新的 @defer
和 @stream
指令允许 GraphQL 服务器通过从单个 GraphQL 响应返回多个有效负载来做到这一点。
@defer
指令可以应用于片段扩展和内联片段。它是一种声明式方法,允许开发人员将查询的某些部分标记为非必需立即返回。
以下是一个 @defer
指令的示例
query { person(id: "cGVvcGxlOjE=") { name ...HomeworldFragment @defer(label: "homeworldDefer") }}
fragment HomeworldFragment on Person { homeworld { name }}
有效负载 1
{ "data": { "person": { "name": "Luke Skywalker" } }, "hasNext": true}
有效负载 2
{ "label": "homeworldDefer", "path": ["person"], "data": { "homeworld": { "name": "Tatooine" } }, "hasNext": false}
当 GraphQL 执行引擎遇到 @defer
指令时,它将分叉执行并开始异步解析这些字段。在延迟的有效负载仍在准备过程中,客户端可以接收并处理初始有效负载。当延迟数据量很大、加载成本很高或不在交互的关键路径上时,这非常有用。
与 @defer
类似,@stream
指令也允许客户端在整个结果准备就绪之前接收数据。@stream
可用于列表字段。以下是 @stream
指令的示例
query { person(id: "cGVvcGxlOjE=") { name films @stream(initialCount: 2, label: "filmsStream") { title }}
有效负载 1
{ "data": { "person": { "name": "Luke Skywalker", "films": [ { "title": "A New Hope" }, { "title": "The Empire Strikes Back" } ] } }, "hasNext": true}
有效负载 2
{ "label": "filmsStream", "path": ["person", "films", 2], "data": { "title": "Return of the Jedi" }, "hasNext": true}
有效负载 3
{ "label": "filmsStream", "path": ["person", "films", 3], "data": { "title": "Revenge of the Sith" }, "hasNext": false}
当 GraphQL 执行引擎遇到 @stream
指令时,它将解析由 initialCount
参数指定的尽可能多的列表项。其余部分将异步解析。这对于仅在折线以上渲染少量元素的界面特别有用。客户端可以尽快渲染这些元素,而服务器仍在解析其余数据。
虽然 GraphQL 规范没有指定传输协议,但我们预计使用 @defer
/@stream
的查询最常见的传输协议是带有分块传输编码的 HTTP。这允许 GraphQL 服务器保持标准的 HTTP 连接打开,同时在每个有效负载准备就绪后立即将其流式传输到客户端。它开销低,几十年来一直受到浏览器的支持,并且可以轻松地与大多数基础设施一起使用。
您可以在以下位置了解更多关于这些指令的信息:
– Rob Richard, Liliana Matos, 前端工程,1stDibs.com