本文目录导读:

浏览器环境 (JavaScript)
使用 CustomEvent API
// 创建自定义事件
class EventManager {
constructor() {
this.events = {};
}
// 注册事件监听
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
// 返回取消订阅函数
return () => {
this.events[eventName] = this.events[eventName].filter(cb => cb !== callback);
};
}
// 触发事件
emit(eventName, data) {
const callbacks = this.events[eventName];
if (callbacks) {
callbacks.forEach(callback => {
callback(data);
});
}
}
// 移除特定事件的所有监听
off(eventName) {
delete this.events[eventName];
}
}
// 使用示例
const eventBus = new EventManager();
// 注册回调
const unsubscribe = eventBus.on('userLogin', (userData) => {
console.log('用户登录:', userData);
// 执行自定义脚本
executeCustomScript(userData);
});
// 触发事件
eventBus.emit('userLogin', {
id: 1,
name: '张三',
timestamp: Date.now()
});
使用浏览器原生 CustomEvent
// 创建自定义事件
function createCustomEvent(eventName, detail) {
return new CustomEvent(eventName, {
detail: detail,
bubbles: true,
cancelable: true
});
}
// 监听事件
document.addEventListener('myCustomEvent', (event) => {
console.log('自定义事件触发:', event.detail);
executeScript(event.detail.script);
}, false);
// 触发事件
function triggerCustomEvent(scriptData) {
const event = createCustomEvent('myCustomEvent', {
source: 'user-action',
script: scriptData,
timestamp: Date.now()
});
document.dispatchEvent(event);
}
// 动态执行脚本
function executeScript(scriptContent) {
try {
// 方式1: 使用 eval
eval(scriptContent);
// 方式2: 创建 script 元素
const script = document.createElement('script');
script.textContent = scriptContent;
document.body.appendChild(script);
document.body.removeChild(script);
} catch (error) {
console.error('脚本执行失败:', error);
}
}
Node.js 环境
使用 EventEmitter
const EventEmitter = require('events');
const { exec } = require('child_process');
const fs = require('fs');
class ScriptEventHandler extends EventEmitter {
constructor() {
super();
this.scriptRegistry = new Map();
}
// 注册事件和对应的脚本
registerScript(eventName, scriptPath) {
if (!this.scriptRegistry.has(eventName)) {
this.scriptRegistry.set(eventName, []);
}
this.scriptRegistry.get(eventName).push(scriptPath);
// 自动绑定事件监听
this.on(eventName, async (data) => {
await this.executeScripts(eventName, data);
});
}
// 执行注册的脚本
async executeScripts(eventName, data) {
const scripts = this.scriptRegistry.get(eventName) || [];
for (const scriptPath of scripts) {
try {
if (scriptPath.endsWith('.js')) {
// 执行 JavaScript 文件
const script = require(scriptPath);
if (typeof script === 'function') {
await script(data);
}
} else if (scriptPath.endsWith('.sh') || scriptPath.endsWith('.bat')) {
// 执行 shell 脚本
await this.executeShellScript(scriptPath, data);
}
} catch (error) {
console.error(`脚本 ${scriptPath} 执行失败:`, error);
}
}
}
// 执行 shell 脚本
executeShellScript(scriptPath, data) {
return new Promise((resolve, reject) => {
const env = { ...process.env, EVENT_DATA: JSON.stringify(data) };
const child = exec(scriptPath, { env }, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
console.log(`脚本输出: ${stdout}`);
resolve(stdout);
});
});
}
// 触发事件
trigger(eventName, data) {
console.log(`事件 "${eventName}" 被触发`);
this.emit(eventName, data);
}
}
// 使用示例
const handler = new ScriptEventHandler();
// 注册脚本
handler.registerScript('fileChanged', './scripts/processFile.js');
handler.registerScript('fileChanged', './scripts/backup.sh');
handler.registerScript('error', './scripts/notifyAdmin.sh');
// 触发事件
handler.trigger('fileChanged', {
path: '/path/to/file.txt',
action: 'modified',
timestamp: Date.now()
});
基于配置文件的事件驱动系统
config.json
{
"events": [
{
"name": "user.register",
"scripts": [
{
"type": "javascript",
"path": "./scripts/welcomeEmail.js",
"async": true
},
{
"type": "shell",
"path": "./scripts/logRegistration.sh",
"params": ["username", "email"]
},
{
"type": "python",
"path": "./scripts/updateAnalytics.py",
"params": ["user_id"]
}
],
"conditions": {
"role": "user",
"verified": true
}
},
{
"name": "file.upload",
"scripts": [
{
"type": "javascript",
"code": "console.log('文件上传完成:', data.filename);"
},
{
"type": "shell",
"path": "./scripts/virusScan.sh",
"params": ["filepath"]
}
]
}
]
}
动态事件引擎实现
const fs = require('fs');
const path = require('path');
const { exec, spawn } = require('child_process');
const EventEmitter = require('events');
class DynamicEventEngine extends EventEmitter {
constructor(configPath) {
super();
this.config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
this.initialize();
}
initialize() {
this.config.events.forEach(eventConfig => {
this.on(eventConfig.name, async (data) => {
// 检查条件
if (this.checkConditions(eventConfig.conditions, data)) {
await this.executeScripts(eventConfig.scripts, data);
}
});
});
}
checkConditions(conditions, data) {
if (!conditions) return true;
return Object.entries(conditions).every(([key, value]) => {
if (typeof value === 'function') {
return value(data[key], data);
}
return data[key] === value;
});
}
async executeScripts(scripts, data) {
for (const scriptConfig of scripts) {
try {
await this.executeScript(scriptConfig, data);
} catch (error) {
console.error(`脚本执行失败:`, error);
this.emit('script.error', { scriptConfig, error, data });
}
}
}
async executeScript(scriptConfig, data) {
switch (scriptConfig.type) {
case 'javascript':
return this.executeJavaScript(scriptConfig, data);
case 'shell':
return this.executeShellScript(scriptConfig, data);
case 'python':
return this.executePythonScript(scriptConfig, data);
default:
throw new Error(`不支持的脚本类型: ${scriptConfig.type}`);
}
}
executeJavaScript(scriptConfig, data) {
return new Promise((resolve, reject) => {
try {
if (scriptConfig.path) {
const scriptModule = require(path.resolve(scriptConfig.path));
if (typeof scriptModule === 'function') {
resolve(scriptModule(data));
}
} else if (scriptConfig.code) {
const fn = new Function('data', scriptConfig.code);
resolve(fn(data));
}
} catch (error) {
reject(error);
}
});
}
executeShellScript(scriptConfig, data) {
return new Promise((resolve, reject) => {
const params = (scriptConfig.params || [])
.map(param => data[param])
.filter(p => p !== undefined);
const child = spawn(scriptConfig.path, params, {
env: { ...process.env, EVENT_DATA: JSON.stringify(data) }
});
let output = '';
child.stdout.on('data', (chunk) => { output += chunk; });
child.stderr.on('data', (chunk) => { output += chunk; });
child.on('close', (code) => {
if (code === 0) {
resolve(output);
} else {
reject(new Error(`脚本退出码: ${code}`));
}
});
});
}
executePythonScript(scriptConfig, data) {
return new Promise((resolve, reject) => {
const params = (scriptConfig.params || [])
.map(param => JSON.stringify(data[param]))
.filter(p => p !== undefined);
const child = spawn('python3', [
scriptConfig.path,
...params,
'--data', JSON.stringify(data)
]);
let output = '';
child.stdout.on('data', (chunk) => { output += chunk; });
child.on('close', (code) => {
if (code === 0) {
resolve(JSON.parse(output));
} else {
reject(new Error(`Python脚本退出码: ${code}`));
}
});
});
}
// 触发事件方法
trigger(eventName, data) {
console.log(`触发事件: ${eventName}`);
this.emit(eventName, data);
}
}
// 使用示例
const engine = new DynamicEventEngine('./config.json');
// 触发用户注册事件
engine.trigger('user.register', {
username: 'newuser',
email: 'user@example.com',
user_id: 12345,
role: 'user',
verified: true
});
// 触发文件上传事件
engine.trigger('file.upload', {
filename: 'document.pdf',
filepath: '/uploads/document.pdf',
size: 1024576,
type: 'application/pdf'
});
WebSocket 方式(实时事件触发)
// 服务器端 (Node.js)
const WebSocket = require('ws');
const http = require('http');
class WebSocketEventSystem {
constructor(port = 8080) {
this.server = http.createServer();
this.wss = new WebSocket.Server({ server: this.server });
this.clients = new Set();
this.scripts = new Map();
this.setupWebSocket();
this.server.listen(port);
}
setupWebSocket() {
this.wss.on('connection', (ws) => {
this.clients.add(ws);
ws.on('message', (message) => {
const data = JSON.parse(message);
this.handleMessage(ws, data);
});
ws.on('close', () => {
this.clients.delete(ws);
});
});
}
handleMessage(ws, data) {
switch (data.type) {
case 'register_script':
this.registerScript(data.event, data.script);
break;
case 'trigger_event':
this.triggerEvent(data.event, data.payload);
break;
case 'execute_callback':
this.executeCallback(data.callbackId, data.result);
break;
}
}
registerScript(eventName, script) {
if (!this.scripts.has(eventName)) {
this.scripts.set(eventName, []);
}
this.scripts.get(eventName).push(script);
}
async triggerEvent(eventName, payload) {
const scripts = this.scripts.get(eventName) || [];
// 广播事件给所有客户端
this.broadcast({
type: 'event_triggered',
event: eventName,
payload: payload
});
// 执行本地脚本
for (const script of scripts) {
await this.executeScript(script, payload);
}
}
executeScript(script, payload) {
return new Promise((resolve) => {
if (typeof script === 'function') {
resolve(script(payload));
} else if (typeof script === 'string') {
try {
const fn = new Function('payload', 'resolve', script);
fn(payload, resolve);
} catch (error) {
console.error('脚本执行错误:', error);
resolve(null);
}
}
});
}
broadcast(message) {
const data = JSON.stringify(message);
this.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
}
}
// 客户端 (浏览器)
class EventClient {
constructor(url = 'ws://localhost:8080') {
this.ws = new WebSocket(url);
this.callbacks = new Map();
this.callbackId = 0;
this.setup();
}
setup() {
this.ws.onopen = () => {
console.log('WebSocket 连接已建立');
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleServerMessage(data);
};
}
handleServerMessage(data) {
switch (data.type) {
case 'event_triggered':
// 事件被触发,执行回调
if (this.callbacks.has(data.event)) {
this.callbacks.get(data.event).forEach(callback => {
callback(data.payload);
});
}
break;
}
}
on(eventName, callback) {
if (!this.callbacks.has(eventName)) {
this.callbacks.set(eventName, []);
}
this.callbacks.get(eventName).push(callback);
// 通知服务器注册监听
this.send({
type: 'register_listener',
event: eventName
});
}
trigger(eventName, payload) {
this.send({
type: 'trigger_event',
event: eventName,
payload: payload
});
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
}
}
}
// 使用示例
// 服务器端
const eventSystem = new WebSocketEventSystem(8080);
// 客户端
const client = new EventClient();
client.on('user_action', (data) => {
console.log('用户操作:', data);
// 执行自定义脚本
if (data.script) {
eval(data.script);
}
});
// 触发事件
client.trigger('user_action', {
type: 'click',
element: '#button',
script: 'alert("自定义脚本执行!")'
});
数据库驱动的事件系统
class DatabaseEventSystem {
constructor(db) {
this.db = db;
this.listeners = new Map();
this.setupDatabaseTriggers();
}
setupDatabaseTriggers() {
// 监听数据库变更
this.db.changes({
since: 'now',
live: true,
include_docs: true
}).on('change', (change) => {
this.handleDatabaseChange(change);
});
}
handleDatabaseChange(change) {
const eventName = `db.${change.doc.type}.${change.doc.action || 'modified'}`;
const data = change.doc;
// 执行绑定的脚本
this.executeEventScripts(eventName, data);
}
bindEvent(eventName, scriptConfig) {
if (!this.listeners.has(eventName)) {
this.listeners.set(eventName, []);
}
this.listeners.get(eventName).push(scriptConfig);
}
async executeEventScripts(eventName, data) {
const scripts = this.listeners.get(eventName) || [];
for (const script of scripts) {
await this.runScript(script, data);
}
}
async runScript(scriptConfig, data) {
// 实现脚本执行逻辑
// 可以支持不同的脚本类型
}
}
最佳实践建议
- 异步处理:对于耗时的脚本,使用异步执行
- 错误处理:添加 try-catch 和错误日志
- 安全考虑:
- 限制可执行的脚本类型
- 使用沙箱环境
- 验证脚本来源
- 性能优化:
- 使用事件队列
- 限制并发执行数
- 实现熔断机制
- 调试支持:
- 添加日志记录
- 实现事件追踪
- 提供测试工具
选择合适的实现方式取决于你的具体需求:是浏览器环境、Node.js 后端、还是跨平台的实时系统。