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]);
|
}, [adaptEventToNotification]);
|
||||||
|
|
||||||
|
|
||||||
// ========== 连接到 Socket 服务(⚡ 方案2: 只执行一次) ==========
|
// ========== 连接到 Socket 服务(⚡ 异步初始化,不阻塞首屏) ==========
|
||||||
useEffect(() => {
|
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', () => {
|
socket.on('connect', () => {
|
||||||
@@ -811,7 +819,7 @@ export const NotificationProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.info('NotificationContext', '所有监听器已注册(只注册一次)');
|
logger.info('NotificationContext', '所有监听器已注册');
|
||||||
|
|
||||||
// ========== 获取最大重连次数 ==========
|
// ========== 获取最大重连次数 ==========
|
||||||
const maxAttempts = socket.getMaxReconnectAttempts?.() || Infinity;
|
const maxAttempts = socket.getMaxReconnectAttempts?.() || Infinity;
|
||||||
@@ -821,11 +829,33 @@ export const NotificationProvider = ({ children }) => {
|
|||||||
// ========== 启动连接 ==========
|
// ========== 启动连接 ==========
|
||||||
logger.info('NotificationContext', '调用 socket.connect()');
|
logger.info('NotificationContext', '调用 socket.connect()');
|
||||||
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 () => {
|
return () => {
|
||||||
|
cleanupCalled = true;
|
||||||
logger.info('NotificationContext', '清理 Socket 连接');
|
logger.info('NotificationContext', '清理 Socket 连接');
|
||||||
|
|
||||||
|
// 取消待执行的初始化
|
||||||
|
if (idleCallbackId && 'cancelIdleCallback' in window) {
|
||||||
|
window.cancelIdleCallback(idleCallbackId);
|
||||||
|
}
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
// 清理 reconnected 状态定时器
|
// 清理 reconnected 状态定时器
|
||||||
if (reconnectedTimerRef.current) {
|
if (reconnectedTimerRef.current) {
|
||||||
clearTimeout(reconnectedTimerRef.current);
|
clearTimeout(reconnectedTimerRef.current);
|
||||||
|
|||||||
@@ -10,25 +10,12 @@ import { socketService } from '../socketService';
|
|||||||
export const socket = socketService;
|
export const socket = socketService;
|
||||||
export { socketService };
|
export { socketService };
|
||||||
|
|
||||||
// ⚡ 新增:暴露 Socket 实例到 window(用于调试和验证)
|
// ⚡ 暴露 Socket 实例到 window(用于调试和验证)
|
||||||
|
// 注意:移除首屏加载时的日志,避免阻塞感知
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
window.socket = socketService;
|
window.socket = socketService;
|
||||||
window.socketService = socketService;
|
window.socketService = socketService;
|
||||||
|
// 日志已移除,如需调试可在控制台执行: console.log(window.socket)
|
||||||
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(
|
|
||||||
'%c[Socket Service] Using REAL Socket Service',
|
|
||||||
'color: #4CAF50; font-weight: bold; font-size: 12px;'
|
|
||||||
);
|
|
||||||
|
|
||||||
export default socket;
|
export default socket;
|
||||||
|
|||||||
Reference in New Issue
Block a user