Fiber 缓存机制
一、缓存上下文
// Intentionally not named imports because Rollup would
// use dynamic dispatch for CommonJS interop named imports.
// 故意不使用命名导入,因为 Rollup 会
// 对 CommonJS 的命名导入使用动态分发。
const {
unstable_scheduleCallback: scheduleCallback,
unstable_NormalPriority: NormalPriority,
} = Scheduler;
export const CacheContext: ReactContext<Cache> = {
$$typeof: REACT_CONTEXT_TYPE,
// We don't use Consumer/Provider for Cache components. So we'll cheat.
// 我们不会为缓存组件使用 Consumer/Provider。所以我们会作弊。
Consumer: (null: any),
Provider: (null: any),
// We'll initialize these at the root.
// 我们将在根节点初始化这些。
_currentValue: (null: any),
_currentValue2: (null: any),
_threadCount: 0,
};
if (__DEV__) {
CacheContext._currentRenderer = null;
CacheContext._currentRenderer2 = null;
}
二、创建缓存
// Creates a new empty Cache instance with a ref-count of 0. The caller is responsible
// for retaining the cache once it is in use (retainCache), and releasing the cache
// once it is no longer needed (releaseCache).
// 创建一个新的空 Cache 实例,引用计数为 0。调用者负责在缓存使用时保留它(retainCache),
// 并在不再需要时释放缓存
export function createCache(): Cache {
return {
controller: new AbortControllerLocal(),
data: new Map(),
refCount: 0,
};
}
三、保留缓存
export function retainCache(cache: Cache) {
if (__DEV__) {
if (cache.controller.signal.aborted) {
console.warn(
'A cache instance was retained after it was already freed. ' +
'This likely indicates a bug in React.',
);
}
}
cache.refCount++;
}
四、释放缓存
// 清理缓存实例,如果没有更多引用,可能会释放它
// Cleanup a cache instance, potentially freeing it if there are no more references
export function releaseCache(cache: Cache) {
cache.refCount--;
if (__DEV__) {
if (cache.refCount < 0) {
console.warn(
'A cache instance was released after it was already freed. ' +
'This likely indicates a bug in React.',
);
}
}
if (cache.refCount === 0) {
scheduleCallback(NormalPriority, () => {
cache.controller.abort();
});
}
}
五、推送缓存提供者
export function pushCacheProvider(workInProgress: Fiber, cache: Cache) {
pushProvider(workInProgress, CacheContext, cache);
}
六、弹出缓存提供者
export function popCacheProvider(workInProgress: Fiber, cache: Cache) {
popProvider(CacheContext, workInProgress);
}
七、工具
1.本地中止控制器
// In environments without AbortController (e.g. tests)
// replace it with a lightweight shim that only has the features we use.
// 在没有 AbortController 的环境中(例如测试环境)
// 用一个轻量级的 shim 替代它,只包含我们使用的功能。
const AbortControllerLocal: typeof AbortController =
typeof AbortController !== 'undefined'
? AbortController
: function AbortControllerShim() {
const listeners = [];
const signal = (this.signal = {
aborted: false as boolean,
addEventListener: (type, listener) => {
listeners.push(listener);
},
});
this.abort = () => {
signal.aborted = true;
listeners.forEach(listener => listener());
};
};