关于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
<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 版本)
- npm 不好用, 安装请用
另一个问题则过度设计, 比方说BrowserDomAdapter extends GenericBrowserDomAdapter(abstract) extends DomAdapter(abstract)
不管怎么说, Angular 确实是造了一套不错的东西,尽管有没有必要这么做实在令人怀疑