new.target 无法用于异步迭代材质派生,因其仅在同步构造时存在,不支持资源加载、状态等待等异步场景;材质派生需基于 effectasset 加载完成后的动态配置与校验。

new.target 无法用于实现“异步迭代材质派生”。
原因很直接:
-
new.target是 JavaScript 运行时的一个同步、构造期元属性,仅在函数作为构造函数被new调用时存在,值为当前正在构造的类/函数本身; - 它不支持异步上下文(不能出现在
async函数中作为构造检测依据),也不能参与资源加载、状态等待或循环派生逻辑; - 材质派生在 Cocos Creator、Unity 等引擎中本质是基于 EffectAsset 实例化 Material 并差异化配置 defines / technique / states 的过程,该过程天然依赖资源加载完成、shader 元信息可用、GPU pipeline 兼容等异步就绪条件——这些与
new.target完全无关。
所以,“利用 new.target 实现异步迭代材质派生”这一说法在技术上不成立,属于概念错配。
真正可行的异步材质派生实践方式
✅ 基于资源加载状态驱动批量创建
Material 实例必须绑定已加载有效的 EffectAsset。异步派生应围绕 resources.load 或 assetManager.loadAny 展开:
- 先统一预加载所有目标 Effect 资源(支持 Promise.all);
- 加载成功后,遍历配置列表,为每个变体调用
new Material()并立即设置effectAsset、technique、define等; - 每次设置后建议检查
material.passes.length > 0或捕获material.validate()返回值,确认 shader 绑定有效。
const effects = await Promise.all([
assetManager.loadAny('effects/pbr.effect') as Promise<effectasset>,
assetManager.loadAny('effects/unlit.effect') as Promise<effectasset>,
]);
const materials: Material[] = [];
for (const effect of effects) {
const mat = new Material();
mat.effectAsset = effect;
mat.technique = 0;
mat.define('USE_NORMAL_MAP', true);
if (!mat.validate()) {
console.warn('Material validation failed for', effect.name);
continue;
}
materials.push(mat);
}</effectasset></effectasset>
✅ 使用 define 组合做轻量级“派生迭代”
不必为每个宏组合新建类或构造函数。通过动态切换 defines,同一 EffectAsset 可支撑数十种视觉变体:
- 构建 define 配置表(如
[{ USE_FOG: true, USE_SHADOW: false }, { USE_FOG: false, USE_SHADOW: true }]); - 异步加载 Effect 后,循环应用各组 define,并调用
mat.recompile()或触发重编译流程(Cocos v3.0+ 需显式调用); - 所有操作均在
Material实例层面完成,无类继承或new.target参与。
✅ 避免封装“派生类”带来的误导性设计
强行写类似 class PBRMetallicMaterial extends Material 并在构造器里用 new.target 做校验:
- 无法阻止传入 null effectAsset;
- 无法防止 technique 索引越界;
- 无法确保 defines 名称拼写正确或类型匹配;
- 引擎底层根本不识别该继承关系——
Material类自身不是靠new.target做安全控制的。
真正健壮的做法是:把校验逻辑放在资源绑定后、渲染前,而非构造时刻。
为什么不要在材质派生中引入 new.target
- 它只能回答一个问题:“这次是不是用 new 调用的?”——而图形引擎中
new Material()本就是唯一合法方式,禁止非 new 调用并无实际防护价值; - 所有导致渲染失败的核心问题(资源未加载、technique 缺失、define 类型错配、pipeline state 漏设)都发生在
new之后,new.target完全不可见; - 引擎内部(如 Cocos 的
Material.ts)也从未使用new.target做任何关键判断,它的存在对材质系统零影响。
聚焦资源生命周期、shader 元信息校验、defines 同步机制和 pipeline state 显式声明,才是让材质派生既灵活又安全的关键。










