内存管理
了解如何选择和设置自定义缓存大小
缓存大小
为了更好的性能,Apollo 客户端 缓存(或者说,记忆)许多内部计算值。在大多数情况下,这些值被缓存在弱缓存,这意味着如果源对象被垃圾回收,缓存的值也将被垃圾回收。
这些缓存也是最近最少使用(LRU)缓存,意味着如果缓存已满,最少的最近使用值将被垃圾回收。
根据您的应用程序,您可能需要调整缓存大小以适应您的需求。
您可以在加载 Apollo 客户端库之前之前(建议)或加载库之后之后设置您的缓存大小。Apollo Client。
在加载 Apollo 客户端库之前设置缓存大小
在加载 Apollo 客户端库之前设置缓存大小是推荐的,因为一些缓存在库加载时已经初始化。更改的缓存大小只会影响事后创建的缓存,所以您需要编写额外的运行时代码来在更改大小后重新创建这些缓存。
import type { CacheSizes } from '@apollo/client/utilities';globalThis[Symbol.for("apollo.cacheSize")] = {parser: 100,"fragmentRegistry.lookup": 500} satisfies Partial<CacheSizes>
在加载 Apollo 客户端库后调整缓存大小
也可以在加载库后调整缓存大小。
import { cacheSizes } from '@apollo/client/utilities';import { print } from '@apollo/client'cacheSizes.print = 100;// cache sizes changed this way will only take effect for caches// created after the cache size has been changed, so we need to// reset the cache for it to be effectiveprint.reset();
选择合适的缓存大小
所有可配置的缓存都持有 memo化的值。如果一个项被缓存收集,它只会产生微小的性能影响,而不会造成数据丢失。较小的缓存大小可能会节省您内存。
您应该选择合适的缓存大小来存储合理数量的值,而不仅仅是每个值。为了避免过多的重新计算,选择足以在任意时刻存储屏幕上所有挂钩/查询的 memoized 值的缓存大小。
为了选择适合我们的 memoization 缓存的好大小,您需要了解它们使用什么作为源值,并对 Apollo 客户端内部的数据流有一般了解。
对于大多数 memoized 值,源值是一个解析的 GraphQL 文档—一个DocumentNode
。有两种类型:
- 用户提供的
DocumentNode
是由用户创建的,例如,通过使用gql
模板字面量标签。这是QUERY
、MUTATION
或SUBSCRIPTION
useQuery
钩子 或作为client.query
的query
选项。 - 转换后的
DocumentNode
是由用户提供的DocumentNode
派生而来,例如,通过应用DocumentTransform
等工具。
通常情况下,您应将使用转换后的 DocumentNode
的缓存大小设置为与使用用户提供的 DocumentNode
的缓存大小相同的水平。如果您的应用程序使用不总是将相同输入转换为相同输出的自定义 DocumentTransform
,则应将使用转换后的 DocumentNode
的缓存大小设置为使用用户提供的 DocumentNode
的缓存大小以上的值。
默认情况下,Apollo Client 为使用用户提供的 DocumentNode
实例的缓存使用 1000 个缓存对象作为基础值,并将其他缓存大小相对于此进行缩放。例如,用户提供的 DocumentNode
的默认基础值 1000 将根据执行的转换,分别缩放到 2000、4000 等。
对于大多数应用程序,这个基础值应该已经足够,但如果您有不同的需求,您可以根据需要进行调整。
测量缓存使用率
由于为应用程序估计合适的缓存大小可能很困难,因此 Apollo Client 提供了一个用于缓存使用率测量的 API。
这样,您可以在应用程序中四处点击,然后查看缓存存储的实际使用情况。
请注意,此 API 主要用于与 Apollo DevTools(即将推出集成)一起使用,并且 API 可能随时更改。
它仅包含在开发构建中,不包括在生产构建中。
ⓘ 注意
缓存使用 API 仅用于手动测量。不要在生产代码或测试中依赖它。
console.log(client.getMemoryInternals())
以下 JSON 格式输出日志
了解更多...
{limits: {parser: 1000,canonicalStringify: 1000,print: 2000,'documentTransform.cache': 2000,'queryManager.getDocumentInfo': 2000,'PersistedQueryLink.persistedQueryHashes': 2000,'fragmentRegistry.transform': 2000,'fragmentRegistry.lookup': 1000,'fragmentRegistry.findFragmentSpreads': 4000,'cache.fragmentQueryDocuments': 1000,'removeTypenameFromVariables.getVariableDefinitions': 2000,'inMemoryCache.maybeBroadcastWatch': 5000,'inMemoryCache.executeSelectionSet': 10000,'inMemoryCache.executeSubSelectedArray': 5000},sizes: {parser: 26,canonicalStringify: 4,print: 14,addTypenameDocumentTransform: [{cache: 14,},],queryManager: {getDocumentInfo: 14,documentTransforms: [{cache: 14,},{cache: 14,},],},fragmentRegistry: {findFragmentSpreads: 34,lookup: 20,transform: 14,},cache: {fragmentQueryDocuments: 22,},inMemoryCache: {executeSelectionSet: 4345,executeSubSelectedArray: 1206,maybeBroadcastWatch: 32,},links: [{PersistedQueryLink: {persistedQueryHashes: 14,},},{removeTypenameFromVariables: {getVariableDefinitions: 14,},},],},}
缓存选项
该函数用用户提供的 片段定义调用。
此函数从 readFragment
使用用户提供的 片段 定义调用。
"documentTransform.cache"
缓存大小设置 cache
选项为 true
时。
可以与用户定义的或已转换的 DocumentNode
调用。
在此处选择缓存大小时应考虑其他DocumentTransform
。例如,如果有一个会接收 x
个DocumentNode
并根据应用程序在线或离线返回不同转换的DocumentNode
的DocumentTransform
,则我们假设缓存返回2*x
个文档。如果将其与另一个会重复缓存大小的DocumentTransform
连接,则需要考虑第二个转换返回的4*x
个文档。
由于 Apollo Client 的实现细节,如果您使用自定义的 文档转换 ,应始终将用户提供的“基本”文档数n
添加到结果缓存大小中。
如果我们假设用户提供的转换接收 n
个文档并返回 n
个文档,则缓存大小应为 2*n。
如果我们假设用户提供的转换链接收 n
个文档并返回 4*n
个文档,则缓存大小应为 5*n。
此大小还应用于提及操作“转换”DocumentNode
的每个其他缓存。
此方法的缓存大小为 FragmentRegistry
。
该函数使用转换后的 DocumentNode
调用,以及递归地使用引用了该片段或将片段引用为片段的每个片段。
注意:fragmentRegistry.transform
的依赖项是该函数,因此在此处的缓存大小过小可能会无意中使transform
缓存中的值无效。
FragmentRegistry 内部的缓存FragmentRegistry
。
此函数以字符串形式使用的片段名称调用。
此情况的大小应考虑您应用程序中的片段数量。
注意:fragmentRegistry.transform
的依赖项是该函数,因此在此处的缓存大小过小可能会无意中使transform
缓存中的值无效。
FragmentRegistry 内部的缓存FragmentRegistry
。
可以与用户定义的或已转换的 DocumentNode
调用。
为“executeSelectionSet
方法在StoreReader
”上的缓存大小。
注意:executeSelectionSet
将设置为resultCacheMaxSize
选项,如果未设置该选项则回退到该配置值。
从缓存中读取的每个对象都将在这里缓存,因此建议将其设置为高值。
为“executeSubSelectedArray
方法在StoreReader
”上的缓存大小。
注意:executeSubSelectedArray
将设置为resultCacheMaxSize
选项,如果未设置该选项则回退到该配置值。
从缓存中读取的每个数组都将在这里缓存,因此建议将其设置为高值。
为“maybeBroadcastWatch
方法在InMemoryCache
”上的缓存大小。
注意:maybeBroadcastWatch
将设置为resultCacheMaxSize
选项,如果未设置该选项则回退到该配置值。
此方法用于在InMemoryCache
中进行依赖项跟踪,并防止不必要的重新渲染。建议将此值设置得显着高于您在任何时候将拥有的活动订阅者数量。
Apollo 客户端内部的一个缓存QueryManager
.
它使用转换后的DocumentNode
调用。
在 removeTypenameFromVariables
中使用的缓存
此函数转换 DocumentNode
。
由 canonicalStringify
调用的缓存。
此缓存包含由 canonicalStringify
字符串化的对象的排序键。它使用未排序的键作为键。无论字符串化了多少实际数据,缓存大小都将不会超过应用中遇到的不同对象 shapes 的大小。
数字
数字
由 print
函数使用的缓存。
它使用转换后的DocumentNode
调用。
这种方法用于将由 GraphQL 查询 AST 解析器 gql 解析的 GraphQL 查询转换回 GraphQL 字符串。