window = floaty.rawWindow(
<vertical w='140dp' h='240dp' padding='8dp' bg='#80000000' id='container'>
<button w='50dp' h='40dp' bg='#03E06D' text='测试' textSize='14sp' textColor='#000000' id='btn1' />
</vertical>
)
// 设置悬浮窗属性
window.setPosition(0, 100)
window.setSize(200, 800)
function ceshi(){
return new Promise(resolve => {
console.log('ceshi 执行中...');
setTimeout(() => {
resolve(111)
}, 1000)
})
}
window.btn1.click(() => {
// 按钮1的点击事件
threads.start(function(){
console.log('点击我了');
ceshi().then(res => {
console.log('ceshi 执行完成');
console.log(res)
})
})
})
setInterval(() => {
}, 1000);
为什么遇到这种代码 如果第二次点到店 .then里面的东西会不执行呢
回答
// 文档地址 https://docs.hamibot.com/
你的问题描述中提到:第二次点击按钮时,.then 里的代码不执行。这个问题的根本原因在于你使用了 threads.start() 来启动一个新线程,并在其中调用异步函数 ceshi(),而 Rhino 引擎对多线程 + Promise 的支持存在严重限制。
🔍 问题分析
window.btn1.click(() => {
threads.start(function(){
console.log('点击我了');
ceshi().then(res => {
console.log('ceshi 执行完成');
console.log(res);
})
})
})
你每次点击都通过 threads.start() 创建了一个新的原生线程(非 UI 线程),但在 Hamibot 当前的 JavaScript 引擎(Rhino 1.7.15)中:
- Promise 是非标准实现,且无法跨线程正常工作
then()回调注册后,其执行上下文可能丢失,尤其是在独立线程中- 多个并发
threads.start()可能导致资源竞争或回调未被正确调度 - 某些情况下,第二个线程启动时,第一个线程的 Promise 尚未清理,造成状态混乱
这会导致:虽然 ceshi() 函数内部的 setTimeout 正常运行,但 .then 的回调从未被调用,尤其是第二次点击之后。
✅ 解决方案
✅ 方案一:避免在线程中使用 Promise —— 改为回调方式(推荐)
不要依赖 Promise 和 then,直接使用回调或同步逻辑处理异步任务。
// 文档地址 https://docs.hamibot.com/
window = floaty.rawWindow(
<vertical w='140dp' h='240dp' padding='8dp' bg='#80000000' id='container'>
<button w='50dp' h='40dp' bg='#03E06D' text='测试' textSize='14sp' textColor='#000000' id='btn1' />
</vertical>
)
window.setPosition(0, 100)
window.setSize(200, 800)
function ceshi(callback) {
console.log('ceshi 执行中...');
setTimeout(function () {
console.log('ceshi 完成');
callback(111);
}, 1000);
}
window.btn1.click(() => {
console.log('点击我了');
// 直接调用,无需开启新线程(除非有耗时操作)
ceshi(function (res) {
console.log('ceshi 执行完成:', res);
});
})
⚠️ 如果
ceshi()中没有耗时操作(比如只是延时),完全不需要开线程。UI 点击事件本身不会阻塞脚本主流程。
✅ 方案二:如果必须用线程,请确保不在子线程中依赖 Promise
如果你确实需要在子线程执行耗时任务,可以这样写:
window.btn1.click(() => {
console.log('点击我了');
threads.start(function () {
// 在子线程中模拟耗时任务
sleep(1000); // 模拟1秒耗时
ui.run(function () {
// 回到UI线程更新悬浮窗或输出日志
console.log('耗时任务完成,返回结果: 111');
});
});
})
注意:
sleep()是 Hamibot 提供的阻塞式延迟函数,只能在子线程使用;ui.run()用于将 UI 更新操作放回主线程。
❌ 错误做法总结
| 做法 | 问题 |
|---|---|
new Promise(...) + then(...) |
Rhino 不完整支持 ES6 Promise |
在 threads.start() 中使用 Promise.then |
回调上下文丢失,可能导致不执行 |
| 连续多次点击创建多个线程 | 线程竞争、资源冲突、难以控制 |
✅ 最佳实践建议
- 不要在 Hamibot 脚本中使用
Promise,除非你知道当前环境已支持 V8 或 Nashorn。 - 使用
callback模式替代Promise。 - 如需异步+线程,优先使用
threads.start()+sleep()+ui.run()组合。 - 避免频繁创建线程,可考虑使用线