新闻资讯

新闻资讯 行业动态

前端 DSL 实践指南——内部 DSL 实践的一些坑

编辑:008     时间:2020-02-20

不友好的异常

在 [风格3: 级联属性] 案例中,其实我们没有定义 minutes 这个单位, 如果错误的使用(5).minutes.later,将得到以下错误提示:

Uncaught TypeError: Cannot read property 'later' of undefined

而不是我们预期的类似报错信息:

Uncaught SyntaxError: Unexpected unit minutes

这是由于异常处理机制也遵循宿主语言,在库封装层面做 DSL 抽象依然无法逃脱这个限制,这也是外部 DSL 的优势所在,不过基于 [风格6:动态代理] 提到的 Proxy,我们仍能做一些微不足道的小优化:

const UNITS = ['days','weeks','hours']; const five = new Proxy(new Number(5), {
  get (target, property) { if(UNITS.indexOf(property) === -1){ throw TypeError(`Invalid unit [${property}] after ${target}`)
    }else{ // blablabla }
  }
})

粘贴到控制台并输入 five.minutes,你将看到更友好的错误提示:

Uncaught TypeError: invalid units [minutes] after 5

容易忽视冰山之下的设计

内部 DSL 的设计要点在于表现层是否流畅,而缺乏对底层领域模型的抽象封装要求,这可能导致 DSL 的「核」是缺乏有效设计的。在实践 DSL 时,我们在领域模型这层仍然要遵循最佳编程实践,比如本文 2.weeks.later 背后的 Duration 等领域模型实体。

作者曾为内部一个历史悠久的庞大前端框架扩展了一个类似 jQuery 的流畅 API 的接口(2012 年勿喷),去掉注释仅仅花费了不到 500 行代码,这个绝大部分归功于框架底层的深厚设计功底和一致性,而非我上层的 DSL 语法糖包装。

此外在 DSL 设计中,语法和语义同样重要,上述诸多例子也证明了:语法的简洁不一定带来流畅性,必须要结合语义模型来设计。

关于语法与语义:a || b 和 a or b 语法不同,但语义相同;而 a > b(Java)和a > b(Shell)语法相同,但语义不同

这部分建议在外部 DSL 的设计工作中也同样重要。

编辑器支持

有些内部 DSL 依赖排版来达到最佳表现,绝大部分语言(包括外部 DSL)的自动格式化引擎都是基于语法树解析来实现的,但内部 DSL 就没那么幸运了,由于它在实际语法层面并没有定义,所以经常会发生在编辑器使用「Format Document」后前功尽弃的情况,这类现象在基于缩进的语言中会比较少。

特殊的代码高亮就更难了,即使是自动补全,也需要一些额外的工作才能被支持。



原文链接:https://segmentfault.com/a/1190000021791568

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

回复列表

相关推荐