不能利用 new.target 实现“异步材质安全派生”,因其仅支持同步调用检查,无法处理资源加载、shader校验等异步问题;真正安全需聚焦资源生命周期与数据契约,如预加载、越界防护、显式更新及静态工厂封装。

不能利用 new.target 在图形引擎中实现“异步材质安全派生”——这个目标本身存在概念混淆。new.target 是 JavaScript 的同步运行时元属性,它既不处理异步逻辑,也不参与材质资源加载、着色器校验或渲染管线配置。
new.target 在材质系统中能做什么?
它仅能做最表层的调用方式检查:
- 防止用户误写
MyMaterial()(非new调用),抛出提示性错误 - 在基类构造函数中识别终端子类名(如
new PBRMaterial()时,所有祖先类中new.target.name都是"PBRMaterial") - 配合日志或统计,记录实际被实例化的材质类型
真正导致材质不安全的环节在哪?
图形引擎中材质失效或崩溃,几乎都源于以下异步/数据层面问题,与 new.target 完全无关:
-
EffectAsset 未加载完成:
new Material()传入了 null 或 pending 状态的资源 -
Technique 索引越界:设置
material.technique = 5,但对应 Effect 只有 3 个 technique -
Defines 不同步:修改了宏(如
USE_EMISSIVE)却未调用material.define(),导致 shader 编译结果与 uniform 值错配 -
Pipeline state 缺失:透明材质漏设
blendState,遮罩材质未配depthStencilState
该怎么做才真正有效?
把防护重心从语法调用转向资源生命周期和数据契约:
- 创建材质前,强制等待资源加载:
await resources.load('xxx.effect') - 设置 technique 时加边界判断:
material.technique = Math.min(index, effectAsset.techniques.length - 1) - 所有 defines 修改后,显式触发更新:
material.define(key, value); material.recompile(); - 关键 pipeline state 不依赖默认值,全部在初始化脚本中显式赋值
如果坚持封装异步材质创建,正确姿势是什么?
用静态工厂方法替代构造函数承载异步逻辑:
- 定义
static async create(effectName: string): Promise - 内部先加载资源,再
new Material(),最后配置 defines/technique/state - 构造函数保持轻量、同步、无副作用;所有异步风险由
create方法统一兜底 -
new.target可用于工厂中校验子类类型(如确保调用的是PBRMaterial.create()而非基类),但只是辅助,不是安全核心










