perf: Socket 连接异步化,使用 requestIdleCallback 不阻塞首屏
- NotificationContext: 将 Socket 初始化包裹在 requestIdleCallback 中 - 设置 3 秒超时保护,确保连接不会被无限延迟 - 不支持 requestIdleCallback 的浏览器自动降级到 setTimeout(0) - socket/index.js: 移除模块加载时的 console.log,减少首屏阻塞感知 - 所有页面的首屏渲染都不再被 Socket 连接阻塞 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -649,9 +649,17 @@ export const NotificationProvider = ({ children }) => {
|
||||
}, [adaptEventToNotification]);
|
||||
|
||||
|
||||
// ========== 连接到 Socket 服务(⚡ 方案2: 只执行一次) ==========
|
||||
// ========== 连接到 Socket 服务(⚡ 异步初始化,不阻塞首屏) ==========
|
||||
useEffect(() => {
|
||||
logger.info('NotificationContext', '初始化 Socket 连接(方案2:只注册一次)');
|
||||
let cleanupCalled = false;
|
||||
let idleCallbackId;
|
||||
let timeoutId;
|
||||
|
||||
// ⚡ Socket 初始化函数(将在浏览器空闲时执行)
|
||||
const initSocketConnection = () => {
|
||||
if (cleanupCalled) return; // 防止组件卸载后执行
|
||||
|
||||
logger.info('NotificationContext', '初始化 Socket 连接(异步执行,不阻塞首屏)');
|
||||
|
||||
// ========== 监听连接成功(首次连接 + 重连) ==========
|
||||
socket.on('connect', () => {
|
||||
@@ -811,7 +819,7 @@ export const NotificationProvider = ({ children }) => {
|
||||
}
|
||||
});
|
||||
|
||||
logger.info('NotificationContext', '所有监听器已注册(只注册一次)');
|
||||
logger.info('NotificationContext', '所有监听器已注册');
|
||||
|
||||
// ========== 获取最大重连次数 ==========
|
||||
const maxAttempts = socket.getMaxReconnectAttempts?.() || Infinity;
|
||||
@@ -821,11 +829,33 @@ export const NotificationProvider = ({ children }) => {
|
||||
// ========== 启动连接 ==========
|
||||
logger.info('NotificationContext', '调用 socket.connect()');
|
||||
socket.connect();
|
||||
};
|
||||
|
||||
// ⚡ 使用 requestIdleCallback 在浏览器空闲时初始化 Socket
|
||||
// 降级到 setTimeout(0) 以兼容不支持的浏览器(如 Safari)
|
||||
if ('requestIdleCallback' in window) {
|
||||
idleCallbackId = window.requestIdleCallback(initSocketConnection, {
|
||||
timeout: 3000 // 最多等待 3 秒,确保连接不会延迟太久
|
||||
});
|
||||
logger.debug('NotificationContext', 'Socket 初始化已排入 requestIdleCallback');
|
||||
} else {
|
||||
timeoutId = setTimeout(initSocketConnection, 0);
|
||||
logger.debug('NotificationContext', 'Socket 初始化已排入 setTimeout(0)(降级模式)');
|
||||
}
|
||||
|
||||
// ========== 清理函数(组件卸载时) ==========
|
||||
return () => {
|
||||
cleanupCalled = true;
|
||||
logger.info('NotificationContext', '清理 Socket 连接');
|
||||
|
||||
// 取消待执行的初始化
|
||||
if (idleCallbackId && 'cancelIdleCallback' in window) {
|
||||
window.cancelIdleCallback(idleCallbackId);
|
||||
}
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
// 清理 reconnected 状态定时器
|
||||
if (reconnectedTimerRef.current) {
|
||||
clearTimeout(reconnectedTimerRef.current);
|
||||
|
||||
@@ -10,25 +10,12 @@ import { socketService } from '../socketService';
|
||||
export const socket = socketService;
|
||||
export { socketService };
|
||||
|
||||
// ⚡ 新增:暴露 Socket 实例到 window(用于调试和验证)
|
||||
// ⚡ 暴露 Socket 实例到 window(用于调试和验证)
|
||||
// 注意:移除首屏加载时的日志,避免阻塞感知
|
||||
if (typeof window !== 'undefined') {
|
||||
window.socket = socketService;
|
||||
window.socketService = socketService;
|
||||
|
||||
console.log(
|
||||
'%c[Socket Service] ✅ Socket instance exposed to window',
|
||||
'color: #4CAF50; font-weight: bold; font-size: 14px;'
|
||||
);
|
||||
console.log(' 📍 window.socket:', window.socket);
|
||||
console.log(' 📍 window.socketService:', window.socketService);
|
||||
console.log(' 📍 Socket.IO instance:', window.socket?.socket);
|
||||
console.log(' 📍 Connection status:', window.socket?.connected ? '✅ Connected' : '❌ Disconnected');
|
||||
// 日志已移除,如需调试可在控制台执行: console.log(window.socket)
|
||||
}
|
||||
|
||||
// 打印当前使用的服务类型
|
||||
console.log(
|
||||
'%c[Socket Service] Using REAL Socket Service',
|
||||
'color: #4CAF50; font-weight: bold; font-size: 12px;'
|
||||
);
|
||||
|
||||
export default socket;
|
||||
|
||||
Reference in New Issue
Block a user