Files
frontend/src/hooks/usePrefetch.ts

350 lines
8.0 KiB
TypeScript
Raw Normal View History

/**
* Hook
*
*
*
* -
* -
* -
* -
*/
import { useCallback, useEffect, useRef } from 'react';
import { postManager } from '../stores/postManager';
import { groupManager } from '../stores/groupManager';
import { userManager } from '../stores/userManager';
import { messageManager } from '../stores/messageManager';
// ==================== 预取配置 ====================
/** 预取任务优先级 */
enum Priority {
HIGH = 0,
MEDIUM = 1,
LOW = 2,
}
/** 预取任务接口 */
interface PrefetchTask {
key: string;
executor: () => Promise<any>;
priority: Priority;
}
/** 预取服务类 */
class PrefetchService {
/** 预取任务队列 */
private queue: PrefetchTask[] = [];
/** 是否正在处理队列 */
private isProcessing = false;
/** 最大并发数 */
private readonly MAX_CONCURRENCY = 3;
/** 当前活跃的任务数 */
private activeCount = 0;
/** 是否启用调试日志 */
private readonly DEBUG = __DEV__ || false;
/**
*
* @param task
*/
schedule(task: PrefetchTask): void {
// 检查是否已有相同key的任务
const existingIndex = this.queue.findIndex(t => t.key === task.key);
if (existingIndex >= 0) {
// 如果新任务优先级更高,替换旧任务
if (task.priority < this.queue[existingIndex].priority) {
this.queue[existingIndex] = task;
}
return;
}
// 按优先级插入队列
let insertIndex = this.queue.findIndex(t => t.priority > task.priority);
if (insertIndex === -1) {
insertIndex = this.queue.length;
}
this.queue.splice(insertIndex, 0, task);
this.processQueue();
}
/**
*
*/
private async processQueue(): Promise<void> {
if (this.isProcessing || this.queue.length === 0) return;
this.isProcessing = true;
while (this.queue.length > 0 && this.activeCount < this.MAX_CONCURRENCY) {
const task = this.queue.shift();
if (!task) break;
this.activeCount++;
// 异步执行任务
this.executeTask(task).finally(() => {
this.activeCount--;
this.processQueue();
});
}
this.isProcessing = false;
}
/**
*
*/
private async executeTask(task: PrefetchTask): Promise<void> {
try {
await task.executor();
} catch (error) {
if (this.DEBUG) {
console.warn(`[Prefetch] 任务失败: ${task.key}`, error);
}
}
}
/**
*
*/
clearQueue(): void {
this.queue = [];
}
/**
*
*/
getQueueLength(): number {
return this.queue.length;
}
}
/** 全局预取服务实例 */
const prefetchService = new PrefetchService();
// ==================== 预取函数 ====================
/**
*
* @param types
*/
function prefetchPosts(types: string[] = ['recommend', 'hot']): void {
types.forEach((type, index) => {
prefetchService.schedule({
key: `posts:${type}:1`,
executor: () => postManager.getPosts(type, 1, 20),
priority: index === 0 ? Priority.HIGH : Priority.MEDIUM,
});
});
}
/**
*
*/
function prefetchConversations(): void {
prefetchService.schedule({
key: 'conversations:list',
executor: async () => {
await messageManager.initialize();
await messageManager.fetchConversations(true);
return messageManager.getConversations();
},
priority: Priority.HIGH,
});
// 同时预取未读数
prefetchService.schedule({
key: 'conversations:unread',
executor: async () => {
await messageManager.initialize();
await messageManager.fetchUnreadCount();
return messageManager.getUnreadCount();
},
priority: Priority.HIGH,
});
}
/**
*
*/
function prefetchUserInfo(): void {
prefetchService.schedule({
key: 'users:me',
executor: () => userManager.getCurrentUser(),
priority: Priority.HIGH,
});
}
/**
*
* @param conversationIds ID数组
*/
function prefetchConversationDetails(conversationIds: string[]): void {
conversationIds.forEach(id => {
prefetchService.schedule({
key: `conversations:detail:${id}`,
executor: async () => {
await messageManager.initialize();
return messageManager.fetchConversationDetail(id);
},
priority: Priority.LOW,
});
});
}
/**
*
* @param groupIds ID数组
*/
function prefetchGroupMembers(groupIds: string[]): void {
groupIds.forEach(id => {
prefetchService.schedule({
key: `groups:members:${id}`,
executor: async () => {
const response = await groupManager.getMembers(id, 1, 50);
return response.list || [];
},
priority: Priority.LOW,
});
});
}
/**
*
*
*/
function prefetchOnAppLaunch(): void {
// 高优先级:用户信息
prefetchUserInfo();
// 高优先级:会话列表和未读数
prefetchConversations();
// 中优先级:帖子列表
prefetchPosts(['recommend']);
}
/**
*
*/
function prefetchMessageScreen(): void {
// 获取当前会话列表,预取前几个会话的详情
const conversations = messageManager.getConversations();
const topConversationIds = conversations.slice(0, 5).map((c: any) => c.id);
// 预取会话详情
prefetchConversationDetails(topConversationIds);
// 预取群组成员(如果是群聊)
const groupIds = conversations
.filter((c: any) => c.type === 'group' && c.group?.id)
.slice(0, 3)
.map((c: any) => String(c.group!.id));
prefetchGroupMembers(groupIds);
}
/**
*
*/
function prefetchHomeScreen(): void {
prefetchPosts(['recommend', 'hot', 'latest']);
}
// ==================== React Hook ====================
/**
* Hook
*
* @example
* ```tsx
* const { prefetchOnAppLaunch, prefetchMessageScreen } = usePrefetch();
*
* useEffect(() => {
* prefetchOnAppLaunch();
* }, []);
* ```
*/
export function usePrefetch() {
/** 是否已完成初始预取 */
const hasInitialPrefetched = useRef(false);
/** 预取帖子 */
const prefetchPostsData = useCallback((types?: string[]) => {
prefetchPosts(types);
}, []);
/** 预取会话 */
const prefetchConversationsData = useCallback(() => {
prefetchConversations();
}, []);
/** 预取用户信息 */
const prefetchUserData = useCallback(() => {
prefetchUserInfo();
}, []);
/** 应用启动预取 */
const doPrefetchOnAppLaunch = useCallback(() => {
if (hasInitialPrefetched.current) return;
hasInitialPrefetched.current = true;
prefetchOnAppLaunch();
}, []);
/** 消息页面预取 */
const doPrefetchMessageScreen = useCallback(() => {
prefetchMessageScreen();
}, []);
/** 首页预取 */
const doPrefetchHomeScreen = useCallback(() => {
prefetchHomeScreen();
}, []);
/** 清空预取队列 */
const clearPrefetchQueue = useCallback(() => {
prefetchService.clearQueue();
}, []);
/** 获取队列长度 */
const getQueueLength = useCallback(() => {
return prefetchService.getQueueLength();
}, []);
return {
// 基础预取方法
prefetchPosts: prefetchPostsData,
prefetchConversations: prefetchConversationsData,
prefetchUserInfo: prefetchUserData,
// 场景预取方法
prefetchOnAppLaunch: doPrefetchOnAppLaunch,
prefetchMessageScreen: doPrefetchMessageScreen,
prefetchHomeScreen: doPrefetchHomeScreen,
// 工具方法
clearPrefetchQueue,
getQueueLength,
};
}
// ==================== 导出 ====================
export {
prefetchPosts,
prefetchConversations,
prefetchUserInfo,
prefetchOnAppLaunch,
prefetchMessageScreen,
prefetchHomeScreen,
prefetchService,
};
export default usePrefetch;