You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: site/learn/Learn-Execution.md
+32-38Lines changed: 32 additions & 38 deletions
Original file line number
Diff line number
Diff line change
@@ -6,9 +6,9 @@ permalink: /learn/execution/
6
6
next: /learn/introspection/
7
7
---
8
8
9
-
After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested query, typically as JSON.
GraphQL cannot execute a query without a type system, let's use an example type system to illustrate executing a query. This is a part of the same type system used throughout the examples in these articles:
@@ -47,16 +47,15 @@ In order to describe what happens when a query is executed, let's use an example
47
47
}
48
48
```
49
49
50
-
You can think of each field in a GraphQL query as a function or method of the previous type which returns the next type. In fact, this is exactly how GraphQL works. Each field on each type is backed by a function called the *resolver*which is provided by the GraphQL server developer. When a field is executed, the corresponding *resolver*is called to produce the next value.
If a field produces a scalar value like a string or number, then the execution completes. However if a field produces an object value then the query will contain another selection of fields which apply to that object. This continues until scalar values are reached. GraphQL queries always end at scalar values.
每一个 GraphQL 服务端应用的顶层,必有一个类型代表着所有进入 GraphQL API 可能的入口点,我们将它称之为 *Root* 类型或 *Query* 类型。
56
57
57
-
At the top level of every GraphQL server is a type that represents all of the possible entry points into the GraphQL API, it's often called the *Root* type or the *Query* type.
58
-
59
-
In this example, our Query type provides a field called `human` which accepts the argument `id`. The resolver function for this field likely accesses a database and then constructs and returns a `Human` object.
This example is written in JavaScript, however GraphQL servers can be built in [many different languages](/code/). A resolver function receives three arguments:
72
-
73
-
-`obj` The previous object, which for a field on the root Query type is often not used.
74
-
-`args` The arguments provided to the field in the GraphQL query.
75
-
-`context` A value which is provided to every resolver and holds important contextual information like the currently logged in user, or access to a database.
Let's take a closer look at what's happening in this resolver function.
78
+
让我们来分析一下在这个解析器函数中发生了什么。
81
79
82
80
```js
83
81
human(obj, args, context) {
@@ -87,14 +85,13 @@ human(obj, args, context) {
87
85
}
88
86
```
89
87
90
-
The `context` is used to provide access to a database which is used to load the data for a user by the `id` provided as an argument in the GraphQL query. Since loading from a database is an asynchronous operation, this returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). In JavaScript Promises are used to work with asynchronous values, but the same concept exists in many languages, often called *Futures*, *Tasks* or *Deferred*. When the database returns, we can construct and return a new `Human` object.
91
-
92
-
Notice that while the resolver function needs to be aware of Promises, the GraphQL query does not. It simply expects the `human` field to return something which it can then ask the `name` of. During execution, GraphQL will wait for Promises, Futures, and Tasks to complete before continuing and will do so with optimal concurrency.
Now that a `Human`object is available, GraphQL execution can continue with the fields requested on it.
94
+
现在 `Human`对象已经生成了,但 GraphQL 还是会继续递归执行下去。
98
95
99
96
```js
100
97
Human: {
@@ -104,16 +101,15 @@ Human: {
104
101
}
105
102
```
106
103
107
-
A GraphQL server is powered by a type system which is used to determine what to do next. Even before the `human`field returns anything, GraphQL knows that the next step will be to resolve fields on the `Human` type since the type system tells it that the `human` field will return a `Human`.
Resolving the name in this case is very straight-forward. The name resolver function is called and the `obj` argument is the `new Human`object returned from the previous field. In this case, we expect that Human object to have a `name`property which we can read and return directly.
106
+
在这个例子中,对 name 字段的处理非常的清晰,name 字段对应的解析器被调用的时候,解析器回调函数的 obj 参数是由上层回调函数生成的 `new Human`对象。在这个案例中,我们希望 Human 对象会拥有一个 `name`属性可以让我们直接读取。
110
107
111
-
In fact, many GraphQL libraries will let you omit resolvers this simple and will just assume that if a resolver isn't provided for a field, that a property of the same name should be read and returned.
While the `name` field is being resolved, the `appearsIn` and `starships` fields can be resolved concurrently. The `appearsIn` field could also have a trivial resolver, but let's take a closer look:
Notice that our type system claims `appearsIn` will return Enum values with known values, however this function is returning numbers! Indeed if we look up at the result we'll see that the appropriate Enum values are being returned. What's going on?
127
-
128
-
This is an example of scalar coercion. The type system knows what to expect and will convert the values returned by a resolver function into something that upholds the API contract. In this case, there may be an Enum defined on our server which uses numbers like `4`, `5`, and `6` internally, but represents them as Enum values in the GraphQL type system.
这是一个强制标量的例子。因为类型系统已经被设定,所以解析器函数的返回值必须符合与类型系统对应的 API 规则的约束。在这个案例中,我们可能在服务器上定义了一个枚举类型,它在内部使用像是 4、5 和 6 这样的数字,但在 GraphQL 类型系统中将它们表示为枚举值。
130
125
131
-
## List resolvers
126
+
## 列表解析器
132
127
133
-
We've already seen a bit of what happens when a field returns a list of things with the `appearsIn`field above. It returned a *list* of enum values, and since that's what the type system expected, each item in the list was coerced to the appropriate enum value. What happens when the `starships` field is resolved?
The resolver for this field is not just returning a Promise, it's returning a *list* of Promises. The `Human` object had a list of ids of the `Starships` they piloted, but we need to go load all of those ids to get real Starship objects.
148
-
149
-
GraphQL will wait for all of these Promises concurrently before continuing, and when left with a list of objects, it will concurrently continue yet again to load the `name` field on each of these items.
As each field is resolved, the resulting value is placed into a key-value map with the field name (or alias) as the key and the resolved value as the value, this continues from the bottom leaf fields of the query all the way back up to the original field on the root Query type. Collectively these produce a structure that mirrors the original query which can then be sent (typically as JSON) to the client which requested it.
0 commit comments