关于Angular的一些感想(二)
发表于更新于阅读时长 3 分钟关于 Angular 和更广泛的 JS 框架的一些感想
-
关于模板和 JSX
- 模板要么引入自定义 tag,要么在字符串里写代码,这两者都会带来不少问题
- 但反之,只要有完善的生态(从 parser 到 IDE 插件),那就没有问题
- 由于 Angular 有很多假设(默认使用 TS 和 @angular/cli )而且投入的人力显著的更多,在这方面做的远比 Vue 好,比如有 template type check,template source map(Vue 3 即将有),对应的 VS Code 插件功能也更强大
- JSX 最大的问题在于会使代码变得臃肿且丑陋,当然一些情况下(比如 Cycle.js)使用 JSX 是唯一正确的选择
-
renderFunction (和 JSX)虽然用起来非常爽
- 代价是静态分析几乎不可能
- 因此需要 VDOM 的来降低 reevaluate renderFunciton 的代价
- 带来的当然好处是表达能力远远超出模板而与 JS 接近,非常灵活,同时大大降低了分拆组件的代价
-
使用 VDOM 会带来一些问题
- 其中最显著的是一个组件只能有一个根结点,否则在 diff 的时候 index 就不对了,如果要有多个根结点需要引入 Fragment
- 另一则是不谨慎的更新策略会带来严重的性能问题
-
而模板虽然表达能力受限
- 但是静态分析更加方便。甚至可以做到零运行时(参考 Svelte,Angular Ivy)
- 因此在编译期可以做的事很多,比方说可以把需要追踪的变量数目压缩到 Model ∩ View 的程度。更多的可以参考 Svelte 和 Angular 的实现
- 当然了,即便如此实际上去做的框架也没多少,大部分时候就是正则一通以后 new Function/eval/with(各种花式拼字符串,话说回来,web 不就是拼字符串的领域么)
- 另一个好处是可以实现模板和逻辑分离,这样在浏览组件功能和重构的时候就不会受到冗长的模板的干扰。(猎奇的是,React 生态圈中通过区分聪明/有状态/胖和笨/纯/瘦/函数式组件来达成这点)
- 可以按编译时期分为两种,即 JIT(打包模板和编译器,在运行时编译模板)和 AOT(在编译期编译)。前者的好处只有开发方便,引个 script 就可以进行开发,后者的好处有很多,包括减小运行时体积等等
-
如果使用模板,而且要表达分支和循环结构的话
- 此处分为 string based template 和 dom based template,对于前者(即不需要是合法的 HTML)则可以使用各种形式的控制块,可以参考 Svelte,代价是提高了对编译器的要求
- Angular 开放了强大的结构型指令给开发者使用。在指令内部可以根据模板输入变量(
hp===0
的运算结果)在视图容器(这个元素在 View 中所处的位置)中渲染模板(I am dead!
) - 这样带来的问题是指令无法被外界访问,这使得 else 变得不可能。在 ng4 中加入了 else templateRef 的语法,提供了另一种解决方案
- Vue 中虽然也有类似的机制,但比较弱。因为不能指定 context,所以尽管可以实现分支但不能实现循环
- 更一般的做法是在编译器中对这样的属性进行特殊处理
- Angular 巧妙的通过结合属性型指令和结构型指令实现了 switch
html
<div my-if="hp===0">I am dead!</div>
-
正因为 Anuglar 有完善的 service 机制,React(和 Vue 3)中的 portal 机制是多余的
-
DI 的本质是 dynamic scope,React 里则可以通过 Context 实现类似的效果
-
Angular 简直是谷歌 NIH 综合症泛滥的地方...
- npm 不好用,安装请用ng init,升级请用ng update(默认的版本前缀是~)
- reflect-metadata 也不够好用,所以自己造了个 compiler (还造成了对 tsserver 的强依赖,导致 ts 版本必须配合 Angular 版本)
另一个问题则过度设计,比方说BrowserDomAdapter extends GenericBrowserDomAdapter(abstract) extends DomAdapter(abstract)
不管怎么说,Angular 确实是造了一套不错的东西,尽管有没有必要这么做实在令人怀疑