GraphQL緩存機制解析:打破緩存誤區
您可能聽說過諸如“GraphQL不支持緩存”或“GraphQL不關心緩存”之類的說法。對於許多人來說,這是一個大問題。但事實並非如此。 GraphQL官方文檔中提到了多種緩存技術,可見其開發團隊非常重視緩存及其性能優勢。
本文旨在澄清GraphQL與緩存之間的關係,並介紹不同的緩存技術以及如何利用緩存優化GraphQL查詢。
考慮以下用於獲取帖子及其作者的查詢:
query getPost { post(slug: "working-with-graphql-caching") { id title author { id name avatar } } }
實現GraphQL自動緩存的“秘訣”是__typename
元字段,所有GraphQL API都提供此字段。顧名思義, __typename
返回對象的類型名稱。此字段甚至可以手動添加到現有查詢中,大多數GraphQL客戶端或CDN會自動添加它,例如urql。服務器接收到的查詢可能如下所示:
query getPost { post(slug: "working-with-graphql-caching") { __typename id title author { __typename id name } } }
包含__typename
的響應可能如下所示:
{ data: { __typename: "Post", id: 5, title: "Working with GraphQL Caching", author: { __typename: "User", id: 1, name: "Jamie Barton" } } }
__typename
是GraphQL緩存的關鍵,因為它允許我們緩存結果,並知道它包含Post ID 5和User ID 1。
Apollo和Relay等庫也提供一定程度的內置緩存,用於自動緩存。由於它們已經知道緩存中的內容,因此它們可以利用緩存而不是遠程API來獲取客戶端在查詢中請求的內容。
假設帖子作者使用editPost
變異修改了帖子的標題:
mutation { editPost(input: { id: 5, title: "Working with GraphQL Caching" }) { id title } }
由於GraphQL客戶端會自動添加__typename
字段,因此此變異的結果會立即告訴緩存Post ID 5已更改,並且包含該帖子的任何緩存查詢結果都需要失效:
{ data: { __typename: "Post", id: 5, title: "Working with GraphQL Caching" } }
下次用戶發送相同的查詢時,查詢將從源獲取新數據,而不是使用緩存中的過期結果。
許多GraphQL客戶端不會緩存整個查詢結果。相反,它們會將緩存數據規範化為兩種數據結構:一種將每個對象與其數據關聯起來(例如,Post #5:{…},User #1:{…}等);另一種將每個查詢與其包含的對象關聯起來(例如,getPost:{Post #5,User #1}等)。
請參閱urql關於規範化緩存的文檔或Apollo的“Demystifying Cache Normalization”以了解具體的示例和用例。
GraphQL緩存無法自動處理的一個主要邊緣情況是向列表中添加項目。因此,如果createPost
變異通過緩存,它不知道要將該項目添加到哪個特定列表中。
最簡單的“解決方法”是在變異中查詢父類型(如果存在)。例如,在下面的查詢中,我們查詢了post上的community關係:
query getPost { post(slug: "working-with-graphql-caching") { id title author { id name avatar } # Also query the community of the post community { id name } } }
然後我們也可以從createPost
變異中查詢該community,並使包含該community的任何緩存查詢結果失效:
mutation createPost { createPost(input: { ... }) { id title # Also query and thus invalidate the community of the post community { id name } } }
雖然並不完美,但類型化模式和__typename
元字段是使GraphQL API非常適合緩存的關鍵。
您可能認為所有這些都是權宜之計,GraphQL仍然不支持傳統的緩存。您不會錯。由於GraphQL通過POST請求運行,您需要卸載到應用程序客戶端並使用上述“技巧”來利用GraphQL的現代瀏覽器緩存。
但是,這種方法並不總是可行的,也不是管理客戶端緩存的最佳方法。對於更棘手的情況,GraphQL客戶端需要您手動更新緩存,但像GraphCDN這樣的服務提供了“類似服務器”的緩存體驗,還提供了一個手動清除API,允許您執行以下操作以獲得更好的緩存控制:
# Purge all occurrences of a specific object mutation { purgeUser(id: [5]) }
# Purge by query name mutation { _purgeQuery(queries: [listUsers, listPosts]) }
# Purge all occurrences of a type mutation { purgeUser }
現在,無論您在何處使用GraphCDN端點,都不再需要在移動端、Web端等所有客戶端邏輯中重新實現緩存策略。邊緣緩存使您的API速度非常快,並通過在用戶之間共享緩存並將其與每個用戶的客戶端分開來減少負載。
最近在一個項目中使用了GraphCDN,它幫我處理了客戶端或服務器上的緩存配置,讓我能夠繼續我的項目。例如,我可以將我的端點替換為GraphCDN,並免費獲得查詢複雜性(即將推出)、分析等功能。
那麼,GraphQL是否關心緩存?當然關心!它不僅提供了一些內置的自動緩存方法,而且許多GraphQL庫提供了其他方法來實現和管理緩存。
希望本文能幫助您了解GraphQL緩存機制,以及如何在客戶端實現它,以及如何利用CDN來完成所有工作。我的目標不是說服您在所有項目中都使用GraphQL,但如果您正在選擇查詢語言並且緩存是一個重要因素,請知道GraphQL完全能夠勝任這項任務。
以上是使用GraphQL緩存的詳細內容。更多資訊請關注PHP中文網其他相關文章!