对 C3D 1.1.1 instantiate方法类型的建议

问题描述:

升级到 1.1.1 后,大量使用到 instantiate的位置报错需要修改

问题原因:
1.1.1之前, instantiate的返回类型为 any, 1.1.1起改为了 Node | null

建议:

  1. instantiate 返回类型改为 Node
  2. instantiate 中的异常流程,直接throw Error,而不是返回null (开发者想处理就try catch,不想处理就让错误暴露出来)

建议理由:

1.1.1 的类型更新后,如下的简单用法都会报错(node可能为null)

let node = instantiate(prefab);
parent.addChild(node);

instantiateconsole.log 一般常用,每个调用处都要处理返回为null的异常流程,与开发实际情况不符。
更适合 throw Error

2赞

既然开启了 strictNullCheck,难道不是应该每个地方都做错误检测吗?
就算 if 改成了 try catch,你也应该每次调用都 try catch 才对呀?
总不能引擎把所有错误都按照出现概率进行分类,把出现概率低的错误都改成异常?这样就等于变相降低了 strictNullCheck 的可信度。那万一之后你遇到问题了,你是不是又要抱怨明明开启了 strictNullCheck 可是引擎的类型系统没给出提示?
因此建议你关闭 strictNullCheck。

就算 if 改成了 try catch,你也应该每次调用都 try catch 才对呀?

这个我的理解不太一样:

  1. 通常情况下,调用 instantiate 时不需要处理异常(无论是检测是否为null,或是try catch)
  2. 只有在开发者自己觉得,传入参数可能有风险时,才额外进行 try catch

理由是:

  1. try catch 的前提是处理 预期内 的异常。
  2. 此处 instantiate 的异常,大都由参数 original 不合法引起,是 预期外 的。
  3. 对于传参不合法等预期外错误,抛异常 更加常见

举例:JSON.parse方法

JSON.parse('ABC') 会 throw Error 而非 return null

这样做的 好处 是,开发者可以根据实际情况,自行选择 要不要处理这个异常。

例如,开发者知道 text 来源于前段程序输出,必定合法,则他无需额外try catch
如果 text 来源于用户输入,可能不合法,才额外try catch一层。

同理,如果所有因为传参不合法引发的错误,都应该返回 null 的话,那可能所有方法的返回类型后面,都需要加一个 | null,那么也变相 强制 开发者调用所有方法时都必须处理异常。

提这个建议的原因也是如此:不得不强制 将之前所有调用 instantiate 加上为 null 的保护,而事实上,这些是完全 可预期非必要 的。(为此关闭 strictNullCheck 显然得不偿失)

1赞

好的,今天我们内部也讨论过这个问题。我个人认为异常是一种返回具体错误原因的好方法。只是那样需要引擎对所有错误进行详细的分类和提示。目前出于简化考虑确实还没细化到这个程度,只是无脑返回 null。针对 instantiate 这类 API,将来 确实是可以考虑把错误行为全部采用异常的形式暴露出来。谢谢反馈。

题外话,这个观点我觉得有点双标了。照你这么说,strictNullCheck 就是多余的。
因为 当我们开启 strictNullCheck,我们就是希望无脑假定每个地方都有风险。根本不存在所谓的根据实际情况自行选择要不要处理的能力。
如果我们真的能够预知每个参数是否有风险,又为何需要借助这么一个强制 check 的机制?我们自己难道不懂得先 check null 吗?

你好,经过内部讨论,我们将在 1.2 中调整以下方法的返回值:

  • instantiate()
  • Node.prototype.addComponent()

详见 https://github.com/cocos-creator/engine/pull/6940