Autox.js 等待超时与 until 避免 findOne 死等和 sleep 盲等
脚本里最容易写错的就是等待
写脚本时最常见的两个错误:
// 错误一:死等——如果控件永远不出现,脚本卡死
text("欢迎").findOne();
// 错误二:盲等——sleep 时间要么不够(脚本报错),要么浪费
sleep(3000);
text("欢迎").findOne().click();
Autox.js 提供了主动等待机制,帮你避免这两个坑。
findOne 带超时
// 正确写法:最多等 5 秒
let btn = text("确定").findOne(5000);
if (btn) {
btn.click();
} else {
toast("5 秒内没找到确定按钮");
}
findOne(timeout) 在 timeout 毫秒内持续轮询控件树(通常每秒几次),一旦找到就立即返回,超时返回 null。这比固定 sleep 高效得多——控件 1 秒就出来了,你不用傻等 3 秒。
until:等待控件出现
until() 的语义是"等到这个选择器匹配到控件为止":
// 等到"登录成功"提示出现(最多 10 秒)
let success = text("登录成功").until(10000);
if (success) {
toast("登录成功");
} else {
toast("10 秒内没等到成功提示");
}
和 findOne(timeout) 非常相似,返回值也一样——找到返回控件、超时返回 null。区别在于语义上的意图:
| API | 语义 | 适用场景 |
|---|---|---|
findOne(timeout) | 查找一个控件 | 我知道它应该在那里,找到它来操作 |
until(timeout) | 等待某个状态变化 | 等异步操作(登录请求、加载动画)完成 |
全局 exists 检查
如果你只是想知道"屏幕上有没有这个控件",不需要等它:
if (text("退出").exists()) {
toast("找到了退出按钮");
} else {
toast("当前页面没有退出按钮");
}
exists() 是瞬间检查,不轮询、不等待。需要等还是用 findOne(timeout) 或 until(timeout)。
处理弹窗和异常页面
脚本跑着跑着可能突然冒出个弹窗(权限请求、广告、更新提示)。主动等待机制能让你提前处理这些情况:
// 在正常等待目标页的同时,监听弹窗
Promise.race([
// 正常路径
text("首页").until(10000),
// 异常路径:权限弹窗
text("允许").until(3000),
text("拒绝").until(3000),
]).then(result => {
if (result === "允许") {
text("允许").findOne().click();
} else if (result === "拒绝") {
text("拒绝").findOne().click();
} else {
toast("正常进入首页");
}
});
sleep 什么时候还能用
sleep() 不应该用来等控件出现,但有几个场景还是需要它:
| 场景 | 为什么需要 sleep |
|---|---|
| 启动 App 后 | launchApp() 不阻塞,App 冷启动需要时间初始化 |
| 网络请求 | 服务器响应时间不可预测,通常用 until() 等结果页 |
| 动画过渡 | 某些界面切换有过渡动画,需要等动画结束再操作 |
| 节流操作 | 某些高频操作(快速点击、快速 scroll)如果不 sleep 可能被系统限流 |
// 典型正确用法
launchApp("com.example.app");
sleep(2000); // 等 App 启动
// 然后用 until 等具体页面
if (!text("首页").until(10000)) {
exit("首页没加载出来");
}
实战:健壮的页面切换
function goToSettings() {
// 点击我的 Tab
let mineTab = text("我的").findOne(10000);
if (!mineTab) {
toast("没找到我的 Tab");
return false;
}
mineTab.click();
// 等待"设置"按钮出现
let settings = text("设置").until(10000);
if (!settings) {
toast("点击我的 Tab 后没等到设置按钮");
return false;
}
settings.click();
// 等待设置页加载
if (!text("通用").until(5000)) {
toast("设置页加载失败");
return false;
}
return true;
}
goToSettings();
总结对比
| API | 是否轮询 | 超时参数 | 返回值 | 适合 |
|---|---|---|---|---|
textExists() | ❌ 瞬间 | 无 | boolean | 瞬间检查 |
findOne() | ✅ 无限等 | 可选 | 控件或 null | 不推荐无超时 |
findOne(timeout) | ✅ 限轮询 | 毫秒数 | 控件或 null | 查找 + 自动等待 |
until(timeout) | ✅ 限轮询 | 毫秒数 | 控件或 null | 等待状态变化 |
sleep(ms) | ❌ 盲等 | 毫秒数 | void | 节流/动画/启动等待 |