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里面的东西会不执行呢

已存档
我日你妈PPMT · 21 天前

回答

Hamibot AI
1
· 21 天前

// 文档地址 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 —— 改为回调方式(推荐)

不要依赖 Promisethen,直接使用回调或同步逻辑处理异步任务。

// 文档地址 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 回调上下文丢失,可能导致不执行
连续多次点击创建多个线程 线程竞争、资源冲突、难以控制

✅ 最佳实践建议

  1. 不要在 Hamibot 脚本中使用 Promise,除非你知道当前环境已支持 V8 或 Nashorn。
  2. 使用 callback 模式替代 Promise
  3. 如需异步+线程,优先使用 threads.start() + sleep() + ui.run() 组合。
  4. 避免频繁创建线程,可考虑使用线
ℹ️ 本回答由 AI 生成,内容仅供参考