前言
在前面的文章中,我们分别完成了前端React应用和后端C++ DLL的开发。本文将详细介绍如何通过koffi库实现JavaScript与C++的无缝集成,这是整个系统最关键的技术环节。我们将深入探讨数据类型转换、错误处理、性能优化等核心实践。
koffi技术方案概述
为什么选择koffi?
koffi是一个现代化的Node.js原生库调用方案,相比传统的node-ffi具有以下优势:
- 性能更优: 基于最新的V8 API,调用开销更小
- 类型安全: 更好的TypeScript支持和类型检查
- 内存管理: 自动的内存管理,减少内存泄漏风险
- 现代API: 支持Promise、async/await等现代异步模式
- 跨平台: 支持Windows、Linux、macOS等多平台
技术架构设计
我们的前后端集成采用三层架构:
Frontend (React/TypeScript)
↓ (IPC)
Electron Main Process (koffi)
↓ (FFI)
C++ DLL (Business Logic)
数据流向:
- React组件调用useBackendAPI Hook
- 通过Electron IPC发送请求到主进程
- 主进程使用koffi调用C++ DLL函数
- C++ DLL处理业务逻辑并返回JSON结果
- 结果通过相同路径返回到React组件
koffi集成实现
1. 主进程koffi配置
在 code/frontend/electron/main.ts
中配置koffi:
typescript
import { koffi } from 'koffi';
import path from 'path';
interface BackendLibrary {
InitLibrary: (configJson: string) => boolean;
ShutdownLibrary: () => void;
AddBook: (bookJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
DeleteBook: (bookId: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
EditBook: (bookJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
GetBookList: (queryJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
BorrowBook: (requestJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
ReturnBook: (requestJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
GetDashboardStats: (resultJson: koffi.Buffer, resultSize: number) => boolean;
}
class BackendManager {
private static instance: BackendManager;
private library: BackendLibrary | null = null;
private initialized = false;
public static getInstance(): BackendManager {
if (!BackendManager.instance) {
BackendManager.instance = new BackendManager();
}
return BackendManager.instance;
}
public initialize(): boolean {
try {
// 确定DLL路径
const dllPath = this.getDllPath();
// 加载DLL
const lib = koffi.load(dllPath);
// 定义函数接口
this.library = {
InitLibrary: lib.func('InitLibrary', 'bool', ['string']),
ShutdownLibrary: lib.func('ShutdownLibrary', 'void', []),
// 图书管理接口
AddBook: lib.func('AddBook', 'bool', ['string', 'char *', 'int']),
DeleteBook: lib.func('DeleteBook', 'bool', ['string', 'char *', 'int']),
EditBook: lib.func('EditBook', 'bool', ['string', 'char *', 'int']),
GetBookList: lib.func('GetBookList', 'bool', ['string', 'char *', 'int']),
// 借阅管理接口
BorrowBook: lib.func('BorrowBook', 'bool', ['string', 'char *', 'int']),
ReturnBook: lib.func('ReturnBook', 'bool', ['string', 'char *', 'int']),
// 仪表板接口
GetDashboardStats: lib.func('GetDashboardStats', 'bool', ['char *', 'int'])
};
// 初始化C++库
const config = {
dbPath: path.join(app.getPath('userData'), 'library.db'),
logPath: path.join(app.getPath('userData'), 'logs'),
maxCacheSize: 1000,
enableDebugLog: process.env.NODE_ENV === 'development'
};
const success = this.library.InitLibrary(JSON.stringify(config));
if (success) {
this.initialized = true;
console.log('Backend library initialized successfully');
}
return success;
} catch (error) {
console.error('Failed to initialize backend library:', error);
return false;
}
}
private getDllPath(): string {
const isDev = process.env.NODE_ENV === 'development';
const basePath = isDev
? path.join(__dirname, '../../dll')
: path.join(process.resourcesPath, 'dll');
const dllName = process.platform === 'win32'
? 'libBackend.dll'
: process.platform === 'darwin'
? 'libBackend.dylib'
: 'libBackend.so';
return path.join(basePath, dllName);
}
public async callFunction<T = any>(
functionName: keyof BackendLibrary,
params?: any
): Promise<{ success: boolean; data?: T; error?: string }> {
if (!this.initialized || !this.library) {
throw new Error('Backend library not initialized');
}
return new Promise((resolve) => {
try {
const resultBuffer = Buffer.alloc(8192); // 8KB缓冲区
let success = false;
// 根据函数类型调用不同的接口
switch (functionName) {
case 'GetDashboardStats':
success = this.library.GetDashboardStats(resultBuffer, resultBuffer.length);
break;
case 'AddBook':
case 'EditBook':
success = this.library[functionName](
JSON.stringify(params),
resultBuffer,
resultBuffer.length
);
break;
case 'DeleteBook':
success = this.library.DeleteBook(
params.id,
resultBuffer,
resultBuffer.length
);
break;
case 'GetBookList':
success = this.library.GetBookList(
JSON.stringify(params || {}),
resultBuffer,
resultBuffer.length
);
break;
case 'BorrowBook':
case 'ReturnBook':
success = this.library[functionName](
JSON.stringify(params),
resultBuffer,
resultBuffer.length
);
break;
default:
resolve({ success: false, error: 'Unknown function' });
return;
}
if (success) {
// 解析返回的JSON数据
const resultStr = resultBuffer.toString('utf8').replace(/\0.*$/g, '');
try {
const result = JSON.parse(resultStr);
resolve({ success: true, data: result });
} catch (parseError) {
resolve({ success: false, error: 'Failed to parse result JSON' });
}
} else {
resolve({ success: false, error: 'Backend function call failed' });
}
} catch (error) {
resolve({
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
});
}
});
}
public shutdown(): void {
if (this.initialized && this.library) {
this.library.ShutdownLibrary();
this.initialized = false;
console.log('Backend library shutdown');
}
}
}
export { BackendManager };
2. IPC通信层
实际项目中的IPC处理器通过 DllBridge
类实现:
typescript
// electron/main.ts 中的主进程配置
import { app, BrowserWindow, ipcMain } from 'electron'
import path from 'node:path'
import { DllBridge } from './dllBridge'
app.whenReady().then(() => {
// 初始化 DLL 桥接器
DllBridge.getInstance();
createWindow()
})
// electron/dllBridge.ts 中的IPC处理
import { ipcMain } from 'electron';
import libGlobalDll from '../src/utils/libGlobalDll';
import dllManager from '../src/utils/dllManager';
export class DllBridge {
private static instance: DllBridge;
private constructor() {
this.setupIpcHandlers();
}
private setupIpcHandlers() {
const bookManager = dllManager.getBookManager();
const readerManager = dllManager.getReaderManager();
// 图书管理相关IPC处理器
ipcMain.handle('dll:getBookList', async (event, jsonInput: string) => {
return await bookManager.getBookList(jsonInput);
});
ipcMain.handle('dll:addBook', async (event, jsonInput: string) => {
return bookManager.addBook(jsonInput);
});
ipcMain.handle('dll:editBook', async (event, jsonInput: string) => {
return bookManager.editBook(jsonInput);
});
ipcMain.handle('dll:deleteBook', async (event, jsonInput: string) => {
return bookManager.deleteBook(jsonInput);
});
// 读者管理相关IPC处理器
ipcMain.handle('dll:getReaderList', async (event, jsonInput: string) => {
return await readerManager.getReaderList(jsonInput);
});
ipcMain.handle('dll:registerReader', async (event, jsonInput: string) => {
return readerManager.registerReader(jsonInput);
});
}
}
3. 前端API封装
在 code/frontend/src/hooks/useBackendAPI.ts
中封装API调用:
typescript
import { useCallback, useRef } from 'react';
interface BackendResponse<T = any> {
success: boolean;
data?: T;
error?: string;
}
// 类型定义
interface Book {
id: string;
title: string;
author: string;
isbn: string;
category: string;
status: 'available' | 'borrowed' | 'reserved' | 'maintenance';
publishDate: string;
addedDate: string;
}
interface BorrowRequest {
bookId: string;
userId: string;
}
interface DashboardStats {
totalBooks: number;
availableBooks: number;
borrowedBooks: number;
totalUsers: number;
activeUsers: number;
activeBorrows: number;
overdueBooks: number;
todayBorrows: number;
todayReturns: number;
borrowTrend: Array<{ date: string; count: number }>;
categoryDistribution: Array<{ category: string; count: number }>;
}
export const useBackendAPI = () => {
const requestIdRef = useRef(0);
const callBackend = useCallback(async <T = any>(
channel: string,
params?: any
): Promise<T> => {
const requestId = ++requestIdRef.current;
const jsonInput = JSON.stringify(params || {});
console.log(`[API Request ${requestId}] ${channel}:`, jsonInput);
try {
const startTime = performance.now();
const result = await window.electronAPI.invoke(channel, jsonInput);
const endTime = performance.now();
console.log(`[API Response ${requestId}] ${channel} (${(endTime - startTime).toFixed(2)}ms):`, result);
return result;
} catch (error) {
console.error(`[API Error ${requestId}] ${channel}:`, error);
throw error;
}
}, []);
// 图书管理API
const bookAPI = {
addBook: useCallback(async (book: Omit<Book, 'id' | 'addedDate'>): Promise<any> => {
return await callBackend('dll:addBook', book);
}, [callBackend]),
getBookList: useCallback(async (query?: {
keyword?: string;
category?: string;
status?: string;
page?: number;
pageSize?: number;
}): Promise<any> => {
return await callBackend('dll:getBookList', query);
}, [callBackend]),
editBook: useCallback(async (book: Partial<Book>): Promise<any> => {
return await callBackend('dll:editBook', book);
}, [callBackend]),
deleteBook: useCallback(async (bookId: string): Promise<any> => {
return await callBackend('dll:deleteBook', { bookId });
}, [callBackend])
};
// 读者管理API
const readerAPI = {
getReaderList: useCallback(async (query?: any): Promise<any> => {
return await callBackend('dll:getReaderList', query);
}, [callBackend]),
registerReader: useCallback(async (reader: any): Promise<any> => {
return await callBackend('dll:registerReader', reader);
}, [callBackend]),
editReader: useCallback(async (reader: any): Promise<any> => {
return await callBackend('dll:editReader', reader);
}, [callBackend]),
deleteReader: useCallback(async (readerId: string): Promise<any> => {
return await callBackend('dll:deleteReader', { readerId });
}, [callBackend])
};
// 状态检查API
const statusAPI = {
checkStatus: useCallback(async (): Promise<any> => {
return await callBackend('dll:checkStatus');
}, [callBackend]),
initAllModules: useCallback(async (): Promise<any> => {
return await callBackend('dll:initAllModules');
}, [callBackend]),
testAllModules: useCallback(async (): Promise<any> => {
return await callBackend('dll:testAllModules');
}, [callBackend])
};
return {
book: bookAPI,
reader: readerAPI,
status: statusAPI
};
};
// Hook使用示例
export const useBooks = () => {
const { book } = useBackendAPI();
return {
addBook: book.addBook,
getBookList: book.getBookList,
editBook: book.editBook,
deleteBook: book.deleteBook
};
};
export const useReaders = () => {
const { reader } = useBackendAPI();
return {
getReaderList: reader.getReaderList,
registerReader: reader.registerReader,
editReader: reader.editReader,
deleteReader: reader.deleteReader
};
};
export const useStatus = () => {
const { status } = useBackendAPI();
return {
checkStatus: status.checkStatus,
initAllModules: status.initAllModules,
testAllModules: status.testAllModules
};
};
数据类型转换与验证
1. TypeScript类型定义
typescript
// src/types/api.ts
export interface APIResponse<T = any> {
success: boolean;
data?: T;
error?: string;
}
export interface PaginatedResponse<T> {
items: T[];
total: number;
page: number;
pageSize: number;
totalPages: number;
}
export interface BookQueryParams {
keyword?: string;
category?: string;
status?: BookStatus;
author?: string;
publishYear?: number;
page?: number;
pageSize?: number;
sortBy?: 'title' | 'author' | 'publishDate' | 'addedDate';
sortOrder?: 'asc' | 'desc';
}
export interface BookCreateRequest {
title: string;
author: string;
isbn: string;
category: string;
publisher: string;
publishDate: string;
description?: string;
coverUrl?: string;
}
export interface BorrowBookRequest {
bookId: string;
userId: string;
duration?: number; // 借阅天数,默认30天
}
2. 数据验证工具
typescript
// src/utils/validation.ts
import { z } from 'zod';
// 图书数据验证模式
export const BookSchema = z.object({
title: z.string().min(1, '书名不能为空').max(200, '书名过长'),
author: z.string().min(1, '作者不能为空').max(100, '作者名过长'),
isbn: z.string().regex(/^(?:\d{9}[\dX]|\d{13})$/, 'ISBN格式不正确'),
category: z.string().min(1, '分类不能为空'),
publisher: z.string().min(1, '出版社不能为空'),
publishDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, '日期格式不正确'),
description: z.string().optional(),
coverUrl: z.string().url('封面URL格式不正确').optional()
});
// 借阅请求验证
export const BorrowRequestSchema = z.object({
bookId: z.string().min(1, '图书ID不能为空'),
userId: z.string().min(1, '用户ID不能为空'),
duration: z.number().min(1).max(90).optional()
});
// 验证函数
export const validateBookData = (data: any): { valid: boolean; errors?: string[] } => {
try {
BookSchema.parse(data);
return { valid: true };
} catch (error) {
if (error instanceof z.ZodError) {
return {
valid: false,
errors: error.errors.map(err => err.message)
};
}
return { valid: false, errors: ['验证失败'] };
}
};
export const validateBorrowRequest = (data: any): { valid: boolean; errors?: string[] } => {
try {
BorrowRequestSchema.parse(data);
return { valid: true };
} catch (error) {
if (error instanceof z.ZodError) {
return {
valid: false,
errors: error.errors.map(err => err.message)
};
}
return { valid: false, errors: ['验证失败'] };
}
};
错误处理机制
1. 统一错误处理
typescript
// src/utils/errorHandling.ts
export enum APIErrorCode {
NETWORK_ERROR = 'NETWORK_ERROR',
VALIDATION_ERROR = 'VALIDATION_ERROR',
BACKEND_ERROR = 'BACKEND_ERROR',
PERMISSION_ERROR = 'PERMISSION_ERROR',
NOT_FOUND = 'NOT_FOUND',
CONFLICT = 'CONFLICT'
}
export interface APIError {
code: APIErrorCode;
message: string;
details?: any;
}
export class APIErrorHandler {
static handleError(error: any): APIError {
console.error('API Error:', error);
// 网络错误
if (error.name === 'TypeError' && error.message.includes('fetch')) {
return {
code: APIErrorCode.NETWORK_ERROR,
message: '网络连接失败,请检查网络状态'
};
}
// 后端返回的错误
if (error.response) {
const { status, data } = error.response;
switch (status) {
case 400:
return {
code: APIErrorCode.VALIDATION_ERROR,
message: data.message || '请求参数错误'
};
case 403:
return {
code: APIErrorCode.PERMISSION_ERROR,
message: '权限不足'
};
case 404:
return {
code: APIErrorCode.NOT_FOUND,
message: '资源不存在'
};
case 409:
return {
code: APIErrorCode.CONFLICT,
message: '数据冲突,请刷新后重试'
};
default:
return {
code: APIErrorCode.BACKEND_ERROR,
message: data.message || '服务器内部错误'
};
}
}
// 默认错误
return {
code: APIErrorCode.BACKEND_ERROR,
message: error.message || '未知错误'
};
}
static createErrorMessage(error: APIError): string {
switch (error.code) {
case APIErrorCode.NETWORK_ERROR:
return '网络连接失败,请检查网络状态后重试';
case APIErrorCode.VALIDATION_ERROR:
return `数据验证失败:${error.message}`;
case APIErrorCode.PERMISSION_ERROR:
return '您没有执行此操作的权限';
case APIErrorCode.NOT_FOUND:
return '请求的资源不存在';
case APIErrorCode.CONFLICT:
return '操作冲突,请刷新页面后重试';
default:
return error.message || '操作失败,请稍后重试';
}
}
}
2. React错误边界
typescript
// src/components/ErrorBoundary.tsx
import React, { Component, ReactNode } from 'react';
import { APIErrorHandler, APIError } from '../utils/errorHandling';
interface ErrorBoundaryState {
hasError: boolean;
error?: APIError;
}
interface ErrorBoundaryProps {
children: ReactNode;
fallback?: (error: APIError) => ReactNode;
}
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
const apiError = APIErrorHandler.handleError(error);
return {
hasError: true,
error: apiError
};
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Error Boundary caught an error:', error, errorInfo);
}
render() {
if (this.state.hasError && this.state.error) {
if (this.props.fallback) {
return this.props.fallback(this.state.error);
}
return (
<div className="flex flex-col items-center justify-center h-64 p-8">
<div className="text-red-500 text-6xl mb-4">
<i className="fas fa-exclamation-triangle"></i>
</div>
<h2 className="text-xl font-semibold text-gray-800 mb-2">
出现错误
</h2>
<p className="text-gray-600 text-center mb-4">
{APIErrorHandler.createErrorMessage(this.state.error)}
</p>
<button
onClick={() => this.setState({ hasError: false, error: undefined })}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
重试
</button>
</div>
);
}
return this.props.children;
}
}
性能优化策略
1. 缓存机制
typescript
// src/hooks/useCache.ts
import { useRef, useCallback } from 'react';
interface CacheEntry<T> {
data: T;
timestamp: number;
expiry: number;
}
export const useCache = <T = any>(defaultExpiry: number = 5 * 60 * 1000) => {
const cache = useRef<Map<string, CacheEntry<T>>>(new Map());
const get = useCallback((key: string): T | null => {
const entry = cache.current.get(key);
if (!entry) return null;
const now = Date.now();
if (now > entry.timestamp + entry.expiry) {
cache.current.delete(key);
return null;
}
return entry.data;
}, []);
const set = useCallback((key: string, data: T, expiry?: number): void => {
cache.current.set(key, {
data,
timestamp: Date.now(),
expiry: expiry || defaultExpiry
});
}, [defaultExpiry]);
const clear = useCallback((pattern?: string): void => {
if (pattern) {
const regex = new RegExp(pattern);
for (const key of cache.current.keys()) {
if (regex.test(key)) {
cache.current.delete(key);
}
}
} else {
cache.current.clear();
}
}, []);
const has = useCallback((key: string): boolean => {
return get(key) !== null;
}, [get]);
return { get, set, clear, has };
};
// 使用缓存的API Hook
export const useCachedBookList = () => {
const { book } = useBackendAPI();
const cache = useCache<{ books: Book[]; total: number }>();
const getBookList = useCallback(async (query?: BookQueryParams) => {
const cacheKey = `books:${JSON.stringify(query || {})}`;
// 尝试从缓存获取
const cached = cache.get(cacheKey);
if (cached) {
return cached;
}
// 从后端获取
const result = await book.getBookList(query);
// 缓存结果
cache.set(cacheKey, result, 2 * 60 * 1000); // 2分钟缓存
return result;
}, [book, cache]);
const invalidateCache = useCallback((pattern?: string) => {
cache.clear(pattern || 'books:');
}, [cache]);
return { getBookList, invalidateCache };
};
2. 请求队列管理
typescript
// src/utils/requestQueue.ts
interface QueuedRequest {
id: string;
promise: Promise<any>;
timestamp: number;
}
class RequestQueue {
private queue: Map<string, QueuedRequest> = new Map();
private maxConcurrent: number = 5;
private currentCount: number = 0;
async enqueue<T>(key: string, requestFn: () => Promise<T>): Promise<T> {
// 如果已经有相同的请求在进行,返回现有的Promise
const existing = this.queue.get(key);
if (existing) {
return existing.promise;
}
// 等待队列有空位
while (this.currentCount >= this.maxConcurrent) {
await new Promise(resolve => setTimeout(resolve, 10));
}
this.currentCount++;
const promise = requestFn()
.finally(() => {
this.queue.delete(key);
this.currentCount--;
});
const request: QueuedRequest = {
id: key,
promise,
timestamp: Date.now()
};
this.queue.set(key, request);
return promise;
}
clear(): void {
this.queue.clear();
this.currentCount = 0;
}
getQueueSize(): number {
return this.queue.size;
}
}
export const requestQueue = new RequestQueue();
// 使用请求队列的Hook
export const useQueuedRequest = () => {
const { book } = useBackendAPI();
const queuedGetBookList = useCallback(async (query?: BookQueryParams) => {
const key = `getBookList:${JSON.stringify(query || {})}`;
return requestQueue.enqueue(key, () => book.getBookList(query));
}, [book]);
return { queuedGetBookList };
};
3. 内存泄漏防护
typescript
// src/hooks/useAbortableRequest.ts
import { useRef, useEffect, useCallback } from 'react';
export const useAbortableRequest = () => {
const abortControllersRef = useRef<Set<AbortController>>(new Set());
const createRequest = useCallback(<T>(
requestFn: (signal: AbortSignal) => Promise<T>
): Promise<T> => {
const controller = new AbortController();
abortControllersRef.current.add(controller);
return requestFn(controller.signal)
.finally(() => {
abortControllersRef.current.delete(controller);
});
}, []);
const abortAll = useCallback(() => {
abortControllersRef.current.forEach(controller => {
controller.abort();
});
abortControllersRef.current.clear();
}, []);
// 组件卸载时取消所有请求
useEffect(() => {
return () => {
abortAll();
};
}, [abortAll]);
return { createRequest, abortAll };
};
// 带取消功能的API Hook
export const useAbortableBookAPI = () => {
const { book } = useBackendAPI();
const { createRequest } = useAbortableRequest();
const getBookList = useCallback(async (query?: BookQueryParams) => {
return createRequest(async (signal) => {
// 这里需要在底层API中支持AbortSignal
return book.getBookList(query);
});
}, [book, createRequest]);
return { getBookList };
};
调试与监控
1. 性能监控
typescript
// src/utils/performance.ts
class PerformanceMonitor {
private metrics: Map<string, number[]> = new Map();
startTiming(operation: string): () => void {
const startTime = performance.now();
return () => {
const endTime = performance.now();
const duration = endTime - startTime;
if (!this.metrics.has(operation)) {
this.metrics.set(operation, []);
}
this.metrics.get(operation)!.push(duration);
// 只保留最近100次记录
const records = this.metrics.get(operation)!;
if (records.length > 100) {
records.shift();
}
console.log(`[Performance] ${operation}: ${duration.toFixed(2)}ms`);
};
}
getAverageTime(operation: string): number {
const records = this.metrics.get(operation);
if (!records || records.length === 0) return 0;
const sum = records.reduce((a, b) => a + b, 0);
return sum / records.length;
}
getMetrics(): Record<string, { average: number; count: number }> {
const result: Record<string, { average: number; count: number }> = {};
for (const [operation, records] of this.metrics) {
result[operation] = {
average: this.getAverageTime(operation),
count: records.length
};
}
return result;
}
}
export const performanceMonitor = new PerformanceMonitor();
// 使用性能监控的Hook
export const useMonitoredBackendAPI = () => {
const { book, loan, dashboard } = useBackendAPI();
const monitoredBook = {
getBookList: useCallback(async (query?: BookQueryParams) => {
const endTiming = performanceMonitor.startTiming('getBookList');
try {
return await book.getBookList(query);
} finally {
endTiming();
}
}, [book]),
addBook: useCallback(async (bookData: any) => {
const endTiming = performanceMonitor.startTiming('addBook');
try {
return await book.addBook(bookData);
} finally {
endTiming();
}
}, [book])
};
return { book: monitoredBook, loan, dashboard };
};
2. 错误上报
typescript
// src/utils/errorReporting.ts
interface ErrorReport {
timestamp: string;
error: string;
stack?: string;
userAgent: string;
url: string;
userId?: string;
additionalInfo?: any;
}
class ErrorReporter {
private reports: ErrorReport[] = [];
private maxReports = 50;
reportError(error: Error, additionalInfo?: any): void {
const report: ErrorReport = {
timestamp: new Date().toISOString(),
error: error.message,
stack: error.stack,
userAgent: navigator.userAgent,
url: window.location.href,
additionalInfo
};
this.reports.push(report);
// 限制报告数量
if (this.reports.length > this.maxReports) {
this.reports.shift();
}
// 在开发环境下输出详细错误信息
if (process.env.NODE_ENV === 'development') {
console.error('Error Report:', report);
}
}
getReports(): ErrorReport[] {
return [...this.reports];
}
clearReports(): void {
this.reports = [];
}
exportReports(): string {
return JSON.stringify(this.reports, null, 2);
}
}
export const errorReporter = new ErrorReporter();
// 全局错误处理
window.addEventListener('error', (event) => {
errorReporter.reportError(event.error, {
filename: event.filename,
lineno: event.lineno,
colno: event.colno
});
});
window.addEventListener('unhandledrejection', (event) => {
const error = event.reason instanceof Error
? event.reason
: new Error(String(event.reason));
errorReporter.reportError(error, {
type: 'unhandledRejection'
});
});
下期预告
在下一篇文章中,我们将深入介绍Google Test单元测试实践,包括如何为C++后端代码编写全面的测试用例,以及如何在CI/CD流程中集成自动化测试。
总结
本文详细介绍了前后端集成的核心技术实践,包括:
- koffi集成方案: 高性能的JavaScript与C++互操作
- IPC通信架构: 安全可靠的进程间通信
- 类型安全设计: 完整的TypeScript类型系统
- 错误处理机制: 统一的错误处理和用户反馈
- 性能优化策略: 缓存、队列管理、内存保护
- 调试监控工具: 性能监控和错误上报
通过这些实践,我们成功实现了前后端的无缝集成,为用户提供了流畅的桌面应用体验,同时保证了系统的稳定性和可维护性。
系列文章目录
- 项目架构设计与技术选型
- 高保真原型设计与用户体验测试
- 前端工程化实践:Electron + React + TypeScript
- 后端C++ DLL开发与模块化设计
- 前后端集成:koffi调用与接口设计
- Google Test单元测试实践
- CMake构建系统与持续集成
- 性能优化与部署发布
通过这个系列文章,您将学习到现代桌面应用开发的完整流程和最佳实践。