JXA脚本批量读取OmniFocus对象耗时过长问题求助
解决JXA操作OmniFocus批量任务的性能问题
我完全懂你遇到的这个痛点!当初我写OmniFocus批量脚本时也踩过一模一样的坑——一开始想当然以为像SQL查询那样一次性把所有任务数据拉到内存里操作,结果几百个任务跑了好几分钟,后来才搞明白问题出在JXA和应用的通信机制上。
问题根源:不是本地对象,是远程通信代理
JXA里通过Application('OmniFocus')获取的任务对象,根本不是内存里的本地对象,而是一个个「远程代理」。每次你访问它的属性(比如task.name()),都会发送一次Apple Event给OmniFocus,等应用返回结果后才能拿到值。如果有上千个任务,就意味着要发上千次单独的请求,性能能不崩吗?
解决方案:一次性批量拉取属性
核心思路是用properties()方法,一次性请求所有需要的属性,把远程代理转换成真正的本地对象数组,之后再操作就完全在内存里了,速度会提升几十甚至上百倍。
低效写法(别用!)
const of = Application('OmniFocus'); // 获取未完成任务的代理数组 const taskProxies = of.defaultDocument.tasks.whose({completed: false})(); // 每个name()都是一次单独的Apple Event,慢到离谱 const taskNames = taskProxies.map(task => task.name());
高效写法(推荐)
const of = Application('OmniFocus'); // 一次性拉取所有未完成任务的name属性,直接得到本地对象数组 const tasks = of.defaultDocument.tasks.whose({completed: false}).properties({name: true}); // 直接从本地对象取属性,秒级完成 const taskNames = tasks.map(task => task.name);
如果需要多个属性(比如同时要name和截止日期),只需要在properties()里指定更多字段:
const tasks = of.defaultDocument.tasks.whose({completed: false}).properties({ name: true, dueDate: true, project: {name: true} // 甚至可以嵌套获取关联对象的属性 });
额外技巧:精准筛选减少数据量
如果任务数量特别大,还可以在whose()里先做更精准的筛选(比如只取某个项目下的任务),减少需要拉取的数据量,进一步提升性能:
const targetProject = of.defaultDocument.projects.whose({name: "工作任务"})()[0]; const tasks = targetProject.tasks.whose({completed: false}).properties({name: true});
总结一下:别把JXA里的应用对象当成普通JS数组处理,一定要利用properties()做批量数据拉取,避免频繁的Apple Event通信——这才是解决这类性能问题的关键!
内容的提问来源于stack exchange,提问作者zambezi
相关产品推荐
相关产品推荐

