英文原版地址:https://www.howtographql.com/...前端
GraphQL一般被认为是前端的API技术,由于它使客户端可以以更好的方式获取数据。 可是既然是API,固然是在服务器端实现的。 由于GraphQL使服务器开发人员可以专一于描述数据,而不是实现和优化特定的接口,因此在服务器上也有不少好处。git
GraphQL经过定义Schema和查询语言,来从Schema中检索数据,但却不只仅是这一种方式。更是一种实际的执行算法,用于将这些查询转换为结果。 该算法的核心很是简单:查询逐字段遍历,为每一个字段执行“解析器”。 让假设咱们有如下模式:github
type Query { author(id: ID!): [Author] } type Author { posts: [Post] } type Post { title: String content: String }
下面是咱们使用该Schema发送到服务器的查询:算法
query { author(id: "abc") { posts { title content } } }
首先要关注的是查询中的每一个字段均可以与一个类型相对应:数据库
query: Query { author(id: "abc"): Author { posts: [Post] { title: String content: String } } }
如今,咱们能够轻松地找到并运行服务器中每一个字段对应的解析器。从查询类型开始执行,并之外层为先。这意味着咱们先运行Query.author
的解析器。而后,咱们将该解析器的结果传递给它的子解析器,Author.posts
的解析器。在下一级,结果是一个列表,在这种状况下,算法会依次在每一个元素上执行一次。因此最终执行工做以下:后端
Query.author(root, { id: 'abc' }, context) -> author Author.posts(author, null, context) -> posts for each post in posts Post.title(post, null, context) -> title Post.content(post, null, context) -> content
最终,执行算法将全部结果数据正确的放在定义好的结构中,并返回。
须要注意的是,大多数GraphQL服务器实现将提供“默认解析器” - 所以您没必要为每一个单个字段指定解析器函数。例如,在GraphQL.js中,当解析器的父对象包含具备正确名称的字段时,不须要指定解析器。
在Apollo博客上的“GraphQL Explained“文章中,可更深刻的了解GraphQL执行状况。服务器
你可能会注意到上述执行策略的一件事是,它有点幼稚。例如,若是你有从后端API或数据库提取的解析器,则在执行一个查询期间可能会屡次调用该后端。让咱们假设,咱们想获取几个帖子的做者,就像这样:函数
query { posts { title author { name avatar } } }
若是这些是博客上的帖子,极可能不少帖子将有相同的做者。因此若是咱们须要一个API调用来获取每一个做者对象,咱们可能会意外地为同一个对象发出多个请求。例如:工具
fetch('/authors/1') fetch('/authors/2') fetch('/authors/1') fetch('/authors/2') fetch('/authors/1') fetch('/authors/2')
咱们如何解决这个问题?让咱们聪明一点。咱们能够将fetch函数封装在一个工具函数中,该实函数将等待全部的解析器运行后,再确保只fetch每一个元素一次:post
authorLoader = new AuthorLoader() // Queue up a bunch of fetches authorLoader.load(1); authorLoader.load(2); authorLoader.load(1); authorLoader.load(2); // Then, the loader only does the minimal amount of work fetch('/authors/1'); fetch('/authors/2');
咱们能作得更好吗?固然,若是咱们的API支持批量请求,咱们只能对后端执行一次提取操做,以下所示:
fetch('/authors?ids=1,2')
这也能够封装在上面的工具函数中。
在JavaScript中,可使用 DataLoader 的工具实现上述策略,其余语言也有相似的工具。