PAYATHON 2026

Shortcuts 中 AppleScript 因 UI 加载缓慢而中止,如何可靠等待?

数据小许

结论

可以使用“条件轮询 + 短间隔 delay”:每隔一小段时间检查目标 UI 元素,元素出现后立即继续执行,无需事先猜测界面的完整加载时间。

原来的代码已经采用了条件轮询。需要调整检查间隔、目标元素的定位,以及等待失败时的处理。AppleEvent handler failed 这条错误本身不足以证明发生了超时,也不能保证仅修改 delay 就能解决问题。

原来的循环为什么仍可能失败?

原代码是:

repeat until UI element 1 exists
    delay 0
end repeat

这里涉及两件事:循环等待元素出现,以及通过 System Events 查询界面。

如果查询正常返回 false,循环可以继续;如果查询本身抛出错误,脚本会在判断条件时中止,不会进入下一次等待。

此外,delay 0 没有提供实际的轮询间隔。改成例如 delay 0.1,可以避免在等待期间连续密集地查询 UI。元素出现后的额外等待通常约为一个轮询间隔,另加查询所需时间。

用短间隔轮询,并设置可选的等待上限

下面以等待 System Settings 的第一个窗口为例。运行前应确保应用已启动。实际使用时,将 exists window 1 换成对目标元素的检查。

-- 示例:最多等待 30 秒。
-- 如需持续轮询,可改为 missing value。
set maxWaitSeconds to 30
set startedAt to current date

repeat
    if maxWaitSeconds is not missing value then
        if ((current date) - startedAt) >= maxWaitSeconds then
            error "等待 System Settings 界面超时。"
        end if
    end if

    -- 为此处的 AppleEvent 调用设置超时。
    with timeout of 10 seconds
        tell application "System Events"
            tell process "System Settings"
                set targetReady to exists window 1
            end tell
        end tell
    end timeout

    if targetReady then exit repeat
    delay 0.1
end repeat

-- 在这里继续执行需要该窗口的操作。

30 秒和 10 秒都是示例值,应按实际情况调整。代码没有吞掉 UI 查询异常:如果 System Events 查询失败,错误会保留下来,便于定位问题。

窗口出现后,里面的按钮、列表或其他控件不一定已经准备好。后续需要点击哪个控件,就应尽量检查该控件,必要时还要检查它是否可用。如果目标路径包含尚未出现的父容器,应先确认父容器存在,再查询其子元素。

区分两种超时

示例中有两种独立的限制:

  • maxWaitSeconds:由脚本主动检查的总等待上限。
  • with timeout:影响块内需要等待响应的 AppleEvent 调用,不是给整个循环设置统一的倒计时。

如果某次查询迟迟没有返回,脚本也无法同时检查总等待时间。因此,总耗时可能超过 maxWaitSeconds,直到当前查询返回或报错。

如果确认是 AppleEvent 等待响应超时,可以按需增大 with timeout 的值。但它不会延长 Shortcuts 或其他调用层可能施加的执行限制,也不能修复应用无响应或失效的 UI 路径。

把 maxWaitSeconds 改为 missing value,只表示取消这段循环自行设置的总等待上限。查询错误、单次 AppleEvent 超时或外部中止仍可能结束执行,不能保证无限等待。

如果仍然出现相同错误

先记录错误发生在哪一次 UI 查询,同时保留错误编号。可以临时在可疑查询外加上:

try
    -- 放入实际的 UI 查询代码。
on error errMsg number errNum
    error ("UI 查询失败,错误编号 " & errNum & ": " & errMsg) number errNum
end try

然后核对目标进程、窗口和控件路径是否仍然有效。使用 UI element 1 时,尤其要确认界面切换后第一个元素是否仍是预期对象。如果能使用明确的控件类型和标识,定位通常更容易维护。

不建议忽略所有查询错误并无限重试,否则权限问题、错误路径和应用退出等情况都会表现为一直等待。只有确认某种错误属于加载过程中的暂时状态,才适合对该错误做有限重试。

备注:内容仅供参考。