回答
Hamibot 目前并不支持真正的双线程并行执行,其运行环境基于 Rhino 引擎,JavaScript 代码在单一线程中执行。你提到的“双线程”可能是指使用了 setInterval 或多个定时任务模拟并发行为。
在使用多个 setInterval 的情况下,随着定时器增多和脚本逻辑复杂化,内存占用会上升,主要原因是:
- 定时器持续持有变量引用,导致无法被回收。
- 多个定时任务频繁执行,造成事件堆积。
- 脚本未及时清理无用对象或未释放资源。
优化建议如下:
1. 减少不必要的 setInterval
每个 setInterval 都会创建一个后台任务,增加运行负担。优先考虑是否可以用 setTimeout 递归调用替代,便于控制生命周期。
// 文档地址 https://docs.hamibot.com/
var timer = setInterval(function () {
// 执行任务
if (/* 满足结束条件 */) {
clearInterval(timer); // 及时清除
}
}, 5000);
务必在不需要时调用 clearInterval 清理定时器,避免内存泄漏。
2. 合并同类任务
将多个小任务合并为一个定时器处理,减少定时器数量。
// 文档地址 https://docs.hamibot.com/
setInterval(function () {
taskA();
taskB();
taskC();
}, 3000);
比分别用三个 setInterval 更节省资源。
3. 避免闭包中的大对象引用
不要在 setInterval 回调中长期持有大量数据或 UI 对象,防止 GC 无法回收。
// ❌ 错误示例:持续引用大数据
var bigData = largeArray();
setInterval(function () {
console.log(bigData[0]); // bigData 一直存在
}, 2000);
应尽量缩小作用域,或只保留必要引用。
4. 使用模块化与函数封装
将逻辑拆分为独立函数,执行完后局部变量可被及时释放。
// 文档地址 https://docs.hamibot.com/
function runTask() {
var temp = "临时变量";
// 任务完成后,temp 会在函数退出后被回收
}
setInterval(runTask, 5000);
5. 主动释放资源
- 不再使用的变量设为
null。 - 解除事件监听(如使用无障碍服务时注意)。
- 脚本结束前调用
hamibot.exit()并清理所有定时器。
// 文档地址 https://docs.hamibot.com/
var id1 = setInterval(task1, 2000);
var id2 = setInterval(task2, 3000);
// 结束时
clearInterval(id1);
clearInterval(id2);
hamibot.exit();
6. 控制脚本频率
避免过于频繁地执行操作(如每 100ms 执行一次),推荐最小间隔不低于 500ms,除非必要。
7. 分离长时间运行脚本
如果功能复杂,建议将不同任务拆分为多个脚本,通过 launchApp 或事件通信方式协作运行,降低单个脚本内存压力。
总结
优化核心是:
- 减少定时器数量
- 及时清理资源
- 避免长时变量引用
- 合理设计执行频率
这样可以显著降低 Hamibot 运行时的内存占用,提升稳定性。
补充回答 1
在 Hamibot 中,可以通过 events.broadcast 实现多个脚本之间的事件通信与协作运行。events.broadcast 是一个全局共享的 EventEmitter,所有正在运行的脚本都可以监听或发送广播事件,从而实现跨脚本通信。
✅ 使用步骤
1. 发送广播事件
在一个脚本中使用 events.broadcast.emit(eventName, ...args) 发送事件。
// 文档地址 https://docs.hamibot.com/
// 发送一个名为 'task_done' 的事件,并携带数据
events.broadcast.emit('task_done', 'login_completed', true);
2. 监听广播事件
在另一个脚本中使用 events.broadcast.on(eventName, callback) 来监听该事件。
// 文档地址 https://docs.hamibot.com/
// 监听 task_done 事件
events.broadcast.on('task_done', function (taskName, success) {
toast('收到任务完成通知: ' + taskName + ', 成功: ' + success);
if (taskName === 'login_completed' && success) {
// 触发后续操作
startMainTask();
}
});
// 保持脚本运行(避免立即退出)
setInterval(() => {}, 1000);
🧩 实际协作示例:登录脚本 + 主任务脚本
假设你有两个脚本:
- 脚本A:负责模拟登录操作。
- 脚本B:等待登录完成后执行主任务。
脚本A:登录完成后发送通知
// 文档地址 https://docs.hamibot.com/
auto.waitFor();
// 模拟登录流程...
toast("开始登录...");
sleep(5000); // 模拟耗时操作
// 登录成功后广播通知
events.broadcast.emit('login_success', {
account: 'user123',
time: new Date().toLocaleString()
});
hamibot.exit(); // 退出当前脚本
脚本B:监听登录成功并继续执行
// 文档地址 https://docs.hamibot.com/
auto.waitFor();
// 监听登录成功的广播
events.broadcast.on('login_success', function (data) {
toast("登录成功,账号:" + data.account + ",时间:" + data.time);
startMainWork(); // 执行主任务
});
function startMainWork() {
// 主业务逻辑
toast("启动主任务...");
// ...
}
// 保持脚本存活以接收事件
setInterval(() => {}, 1000);
只要两个脚本都处于运行状态,就能通过广播进行通信。
⚠️ 注意事项
-
脚本必须正在运行才能接收到事件
如果目标脚本未启动或已结束,则无法收到广播。 -
事件是异步的
广播发出后不会阻塞,也不会确认对方是否处理。 -
避免重复监听
多次调用on会注册多个监听器,建议在合适时机使用off()解除:var listener = function () { ... }; events.broadcast.on('event', listener); // 之后移除 events.broadcast.off('event', listener); -
不要传递函数或复杂对象
参数应为可序列化的数据类型(如字符串、数字、普通对象),避免传入函数、锁、线程等。
✅ 最佳实践建议
- 将公共事件名称统一定义为常量,避免拼写错误。
- 脚本启动时先注册监听,再执行其他逻辑。
- 关键任务完成后及时发送状态通知,提高协作效率。
通过 events.broadcast,你可以轻松实现多脚本协同工作,替代“多线程”场景下的通信需求,同时降低内存压力和逻辑耦合度。