Elm/JS 互操作的限制
许多语言都有一个外国函数接口 (FFI),允许直接绑定寄主语言中的函数。例如,Scala 可以直接调用 Java 函数。Clojure/Java、Python/C、Haskell/C 和许多其他语言也一样。
Elm 没有与 JavaScript 的传统外国函数接口。无法随时调用任意的 JavaScript 函数。这让一些人非常喜欢,但也并不是所有人都喜欢!如果您正在评估 Elm 以用于商业用途,我强烈建议您浏览 这些互操作示例,了解标志、端口和自定义元素是否能涵盖您需要的所有内容。
为什么 Elm 做出了与其他语言不同的选择?
折衷替代
在语言的历史中,端口有点儿像是局外人。有两种常见的互操作策略,而 Elm 都不满足
- 完全向后兼容。例如,C++ 是 C 的超集,而 TypeScript 是 JavaScript 的超集。这是最宽松的方法,而且已被证明非常有效。根据定义,每个人都已经在使用您的语言了。
- 外国函数接口 (FFI) 这允许直接绑定寄主语言中的函数。例如,Scala 可以直接调用 Java 函数。Clojure/Java、Python/C、Haskell/C 和许多其他语言也一样。同样,这已被证明相当有效。
由于两个主要原因,这些路径对于更快地采用和更大的灵活性很有吸引力但对于 Elm 来说并不理想
- 失去保证。使用 Elm 的最大益处之一就是不必担心一系列问题。没有要捕获的意外异常,函数无法以意外的方式修改数据。我认为这是 Elm 高于其他语言的核心价值,但如果我们可以直接调用 JS,那么这一切都将消失。该程序包是否会产生运行时异常?时间是何时?是否会修改我赋给它的值?我需要检测到这一点吗?该程序包是否有副作用?是否会向某些第三方服务器发送消息?记录密码?很大一部分 Elm 用户被吸引到该语言,正是因为他们不必再这么想了。
- 程序包泛滥。对直接将 JavaScript API 复制到 Elm 的需求非常高。在
elm/html
到来之前两年,如果可能的话,我相信有人会贡献 jQuery 绑定。这已经发生在编译到 JS 的类型化函数式语言中,但具有更传统的互操作设计。据我所知,程序包泛滥在某种程度上是编译到 JS 语言特有的。例如,在 Python 中压力没那么大,所以我认为缺点是 JavaScript 生态系统的独特文化和历史的产物。
考虑到这些陷阱,端口和自定义元素非常有吸引力,因为它们允许你用 JavaScript 完成任务,同时保留 Elm 的最佳部分。太棒了!另一方面,这意味着 Elm 无法搭 JS 生态系统的便车获得更多库,速度更快。如果你放眼长远,我认为这实际上是一个关键优势。因此
- 程序包专为 Elm 设计。随着 Elm 社区成员获得更多经验和信心,我们开始看到布局和数据可视化的新方法,这些方法可以与 Elm 架构和整个生态系统无缝协作。我预计针对其他类型的问题,这种情况会不断发生!
- 代码是可移植的。如果编译器有一天产生了 x86 或 WebAssembly,整个生态系统都可以继续工作,但速度更快!端口保证所有程序包完全用 Elm 编写,而 Elm 本身的设计使其他非 JS 编译器目标成为可能。
- 程序包更安全。JavaScript 等语言对程序包有严重的安全性问题。有关窃取凭据和 窃取 API 密钥 的报道并不少见,给所有程序包施加了永久的审计成本。它们向
window
添加了键盘记录器吗?Elm 程序包可以保证一大类漏洞根本不会发生,从而降低整体审计成本和安全风险。 - 优化更轻松。过去,所生成代码的样式随发行版而发生了显著的变化。例如,0.19 发行版 通过(1)以更适合 JavaScript 缩小程序的方式生成代码,以及(2)根据优化级别使用自定义类型的不同运行时表示形式,显著缩减了资源大小。我预计它将会在代码切分时或若我们为柯里化找到更快的调用约定时再次改变。此外,编译器还可以安全地假定所有代码都是纯净的,这可能允许它比其他编译器更积极地移动代码。现在锁定一个特定的调用约定可能会让其中的一些优化变得不可能。
这绝对是一条更长更艰巨的路,但语言的使用寿命超过 30 年。它们必须支持整个团队和公司几十年,当我想到 Elm 在 20 或 30 年后的样子时,我认为随着端口而来的权衡真的很有前景!我的演讲 什么是成功? 开始时有点慢,但它会更深入地探讨这个话题!
再说一次,这条路并不适合所有人!有很多替代语言具有传统的 FFI,如果您认为这条路可能更好,我鼓励您研究这些语言。包生态系统是否像它那样有凝聚力?您是否更经常收到运行时异常?也许吧,但也许额外的灵活性对您来说是值得的。因此我鼓励您了解一下 这些互操作示例,以决定标记、端口和自定义元素是否能涵盖您所需的一切。如果您正在考虑将 Elm 用于商业用途,这一点尤其重要!