Graphql 解析函数中的并行承诺执行
我有一个关于在GraphQL客户机的resolve函数中处理承诺的问题。传统上,解析程序将在服务器上实现,但我正在客户机上包装RESTAPI 背景和动机 给定解析程序,如:Graphql 解析函数中的并行承诺执行,graphql,graphql-js,apollo,Graphql,Graphql Js,Apollo,我有一个关于在GraphQL客户机的resolve函数中处理承诺的问题。传统上,解析程序将在服务器上实现,但我正在客户机上包装RESTAPI 背景和动机 给定解析程序,如: const resolvers = { Query: { posts: (obj, args, context) => { return fetch('/posts').then(res => res.json()); } }, Post: { author: (o
const resolvers = {
Query: {
posts: (obj, args, context) => {
return fetch('/posts').then(res => res.json());
}
},
Post: {
author: (obj, args, _, context) => {
return fetch(`/users/${obj.userId}`)
.then(res => res.json());
.then(data => cache.users[data.id] = data)
}
}
};
如果我运行查询:
posts {
author {
firstName
}
}
而Query.posts()
/posts
API返回四个post对象:
[
{
"id": 1,
"body": "It's a nice prototyping tool",
"user_id": 1
},
{
"id": 2,
"body": "I wonder if he used logo?",
"user_id": 2
},
{
"id": 3,
"body": "Is it even worth arguing?",
"user_id": 1
},
{
"id": 4,
"body": "Is there a form above all forms? I think so.",
"user_id": 1
}
]
Post.author()
解析器将被调用四次以解析author
字段
grapqhl-js
有一个非常好的特性,从Post.author()返回的每个承诺都将并行执行
我还能够使用facebook的库消除使用相同的userId
重新获取作者的行为但是,我想使用自定义缓存而不是数据加载器
问题
有没有办法阻止Post.author()
resolver并行执行?在Post.author()
resolver中,我想一次获取author
s一个,检查中间的缓存以防止重复http请求
但是,现在从Post.author()
返回的承诺会排队并立即执行,因此我无法在每次请求之前检查缓存
谢谢你的提示 我绝对推荐您查看,因为它的设计正是为了解决这个问题。如果不直接使用它,至少可以阅读它的实现(没有那么多行)并借用自定义缓存上的技术
GraphQL和GraphQL.js库本身并不关心加载数据——它们通过解析器函数将这一点留给您。js只是尽可能急切地调用这些解析器函数,以提供最快的查询整体执行速度。您完全可以决定返回按顺序解决的承诺(我不建议这样做),或者在DataLoader使用备忘录实现重复数据消除时返回承诺(这是您解决此问题的目的)
例如:
const resolvers = {
Post: {
author: (obj, args, _, context) => {
return fetchAuthor(obj.userId)
}
}
};
// Very simple memoization
var authorPromises = {};
function fetchAuthor(id) {
var author = authorPromises[id];
if (!author) {
author = fetch(`/users/${id}`)
.then(res => res.json());
.then(data => cache.users[data.id] = data);
authorPromises[id] = author;
}
return author;
}
我绝对推荐你看看,因为它的设计就是为了解决这个问题。如果不直接使用它,至少可以阅读它的实现(没有那么多行)并借用自定义缓存上的技术
GraphQL和GraphQL.js库本身并不关心加载数据——它们通过解析器函数将这一点留给您。js只是尽可能急切地调用这些解析器函数,以提供最快的查询整体执行速度。您完全可以决定返回按顺序解决的承诺(我不建议这样做),或者在DataLoader使用备忘录实现重复数据消除时返回承诺(这是您解决此问题的目的)
例如:
const resolvers = {
Post: {
author: (obj, args, _, context) => {
return fetchAuthor(obj.userId)
}
}
};
// Very simple memoization
var authorPromises = {};
function fetchAuthor(id) {
var author = authorPromises[id];
if (!author) {
author = fetch(`/users/${id}`)
.then(res => res.json());
.then(data => cache.users[data.id] = data);
authorPromises[id] = author;
}
return author;
}
对于一些使用dataSource
和dataLoader
一起使用restapi的人来说(在这种情况下,它并没有真正的帮助,因为它只是一个请求)。下面是一个简单的缓存解决方案/示例
export class RetrievePostAPI extends RESTDataSource {
constructor() {
super()
this.baseURL = 'http://localhost:3000/'
}
postLoader = new DataLoader(async ids => {
return await Promise.all(
ids.map(async id => {
if (cache.keys().includes(id)) {
return cache.get(id)
} else {
const postPromise = new Promise((resolve, reject) => {
resolve(this.get(`posts/${id}`))
reject('Post Promise Error!')
})
cache.put(id, postPromise, 1000 * 60)
return postPromise
}
})
)
})
async getPost(id) {
return this.postLoader.load(id)
}
}
注意:这里我使用内存缓存
作为缓存机制。
希望这能有所帮助。仅适用于使用数据源
和数据加载器
来处理REST api内容的一些人(在本例中,它并没有真正的帮助,因为它只是一个请求)。下面是一个简单的缓存解决方案/示例
export class RetrievePostAPI extends RESTDataSource {
constructor() {
super()
this.baseURL = 'http://localhost:3000/'
}
postLoader = new DataLoader(async ids => {
return await Promise.all(
ids.map(async id => {
if (cache.keys().includes(id)) {
return cache.get(id)
} else {
const postPromise = new Promise((resolve, reject) => {
resolve(this.get(`posts/${id}`))
reject('Post Promise Error!')
})
cache.put(id, postPromise, 1000 * 60)
return postPromise
}
})
)
})
async getPost(id) {
return this.postLoader.load(id)
}
}
注意:这里我使用内存缓存
作为缓存机制。
希望这能有所帮助。未来读者注意:我说的graphql-js
解析器可以通过“并行”执行完成任何事情是错误的。正如Lee在下面所说的,解析函数及其返回的承诺都会急切地执行。在本例中,从Post.author()
resolver返回的所有承诺都同时处于“飞行”状态,这使得我在上面尝试的缓存检查变得不可能。通过某个唯一的键(id
或url
)来记录请求是一种方法,我将使用DataLoader来实现这一点。请未来的读者注意:当我说graphql js
解析器可以“并行”执行时,我错了。正如Lee在下面所说的,解析函数及其返回的承诺都会急切地执行。在本例中,从Post.author()
resolver返回的所有承诺都同时处于“飞行”状态,这使得我在上面尝试的缓存检查变得不可能。通过一些唯一的键(id
或url
)来记忆请求是一种方法,我将使用DataLoader来实现这一点。