/** * 数据预取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; 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 { 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 { 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;