内容提要
在 Photoshop ExtendScript 中,DOM API 遍历 323 个图层耗时近 6 秒,性能极差。改用 ActionManager(AM)可大幅提速:线性自底向上遍历仅需 80ms,快约 50 倍;若需树状自顶向下结构,可借助 layerKind 为 13 的组边界图层重建 n 叉树,耗时约 418ms,仍比 DOM 快近 10 倍。高性能场景应尽量用 AM 替代 DOM API。
延伸解读
DOM API 性能瓶颈的根源
文章通过测试发现,访问 DOM 对象的可写属性(如 name)比纯 JS 对象慢约 130 倍,而只读属性(如 id)同样慢约 126 倍,但 typeName 属性却接近纯对象速度。这表明 DOM 属性访问并非一律缓慢,但大多数常用属性(如 name、id)性能极差。因此,在遍历图层时,应尽量减少对 DOM 属性的访问次数,例如将 layerSet.layers 转换为纯数组,避免在循环中重复访问 length 和索引。
ActionManager 遍历的两种策略
使用 ActionManager(AM)遍历图层有两种方式:线性自底向上遍历和树状自顶向下遍历。线性遍历直接通过 itemIndex 从大到小访问图层,跳过 layerKind 为 13 的组边界图层,速度极快(323 图层仅 80ms),但无法获取层级信息,也不能在遍历到某图层时停止其子图层的遍历。树状遍历则利用组边界图层重建 n 叉树,支持自顶向下和层级操作,但需获取完整 ActionDescriptor 并构造树,耗时约 418ms,仍比 DOM 快近 10 倍。
如何选择遍历方案
如果业务只需线性遍历图层(如收集所有图层 ID),应优先使用 AM 线性遍历,因其速度最快且实现简单。若需要树状结构、自顶向下顺序或层级信息(如知道当前图层的父级、兄弟图层),则需使用 AM 树状遍历。文章指出,树状遍历虽比线性慢,但相比 DOM API 仍有近 10 倍提升。开发者应根据实际需求权衡性能与功能,避免不必要的树构造开销。
Q&A
在 Photoshop ExtendScript 中,为什么用 DOM API 遍历图层树性能很差?
因为 DOM API 访问图层属性时,每次都会与底层 C++ 进行通信以获取最新数据,导致访问速度比纯 JS 对象慢百倍以上。例如,访问 DOM 对象的 name 属性耗时 1586ms,而访问纯 JS 对象的 name 属性仅需 12ms,相差约 132 倍。
使用 ActionManager 线性遍历图层树比 DOM API 快多少?
对于包含 323 个图层的 PSD,使用 ActionManager 线性遍历(自底向上)仅需 80ms,而 DOM API 遍历需要约 4000ms,速度提升约 50 倍。
如何用 ActionManager 实现自顶向下的树状图层遍历?
通过逆序遍历 itemIndex(从大到小),并利用 layerKind 为 13 的组边界图层(HiddenSectionBounder)来确定组的范围,从而重建 n 叉树。具体实现中,递归处理组图层,遇到组边界图层则返回上一层。
ActionManager 线性遍历和树状遍历各有什么优缺点?
线性遍历速度更快(80ms),但只能自底向上,无法获取层级信息或提前终止子图层遍历;树状遍历速度稍慢(418ms),但能自顶向下、保留层级结构,适合需要树形操作的场景。
在 ExtendScript 中,所有 DOM 属性的访问速度都比纯对象慢吗?
不是。大多数只读属性(如 id)访问速度与可写属性一样慢,但少数属性如 typename 的访问速度与纯对象几乎相同(仅慢 1.8 倍),这可能与底层实现有关。
如何优化 DOM API 遍历图层树的性能?
尽量减少 DOM API 的访问次数。例如,将 layerSet.layers 转换为纯数组,避免在循环中重复访问 length 和索引,这样可以将遍历时间从 5894ms 降低到 4539ms。